package test;
public class BitAdd {
/**
* 算法,给定一个二进制数n中1所在的位置,求3*n的二进制表达式中1的所在位置
* 例如 50 的二进制位110010 那么这个二进制数1的位置为{1,4,5},50*3=150 求150的二进制数的1所在位置
* 先利用2*n等于n左移以为,计算出2*n,再2*n+n 得出解,解最终打印出来了。关键步骤就是二进制加法。
*/
public static void main(String[] args) {
int[] A={1,4,5};
int[] B={2,3,4,5};
Bit3Times(A);
System.out.println("");
Bit3Times(B);
}
public static void Bit3Times(int[] A){
int[] B=new int[A.length];
int[] C=new int[A.length+1];
for(int i=0;i<A.length;i++){
B[i]=A[i]+1;
C[i]=A[i];
}
for(int i=0;i<C.length;i++){
if(i<B.length){
for(int j=0;j<B.length;j++){
if(C[i]==B[j]){
C[i]=C[i]+1;
break;
}else if(B[j]<C[i+1]&&B[j]>C[i]){
C[B.length+i]=B[j];
}
}
}
}
if(C[B.length-1]==B[B.length-1]){
C[B.length-1]++;
}
int num=0;
for(int i=0;i<C.length;i++){
if(C[i]>0) num++;
System.out.printf("%s,", C[i]);
}
}
}
Hibernte 1:n 最佳抓取策略
在orm中实体1:n关联时,要考虑两个问题,分别是经典的n+1问题,和笛卡尔积问题。所以要避免使用默认抓取策略,同时尽量减少结果。hibernate作为最主流的java orm。一般的的优化原则是使用batchsize减少子查询的sql数量,同时在one一端使用懒加载,并且用subselect或者join来代替默认的关联加载。
上代码:
@Entity
@BatchSize(size=10)//因为一般要获得post,都会调用creator,所以使用预抓(EAGER)策略,同事设置预抓持为10
public class User extends BaseEntity{
@Id @GeneratedValue
@Column(name="id")
private long id;
@OneToMany(mappedBy="creator",fetch=FetchType.LAZY)//懒加载
@Fetch(FetchMode.SUBSELECT)//使用JOIN会产生笛卡尔积的问题,subselect策略是Hibernate.org推荐的解决N+1问题策略
private Set posts=new HashSet();
......
}
@Entity
public class Post extends BaseEntity {
@Id @GeneratedValue
@Column(name="id")
private long id;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(nullable=false)
private User creator;
....
}
用perl脚本解决ant…非法字符:\65279…的问题
用ant管理项目,编译时发现有些utf8编码的java文件无法编译,
报错是…非法字符:\65279…。
在网上查N多与ant有关的文章,但是大多数的解决方案都不是很理想。因为文件比较多,而且我的
机器上也没有装editplus。
索性自己用perl写了一个脚本
如下:
#remove the utf-8 BOM for Ant
sub remove_bom {
#open( my $in, "+<", "src/com/umpay/wap20/mobileProxy/MobileProxy.java" );
foreach my $filename (@_) {
print $filename,"\n";
open( my $in, "+<", $filename );
@lines = <$in>;
$line1 = $lines[0];
$t_chk1 = substr( $line1, 0, 1 ); #0xef -> 239
$t_chk2 = substr( $line1, 1, 1 ); #0xbb -> 187
$t_chk3 = substr( $line1, 2, 1 ); #0xbf ->191
if ( ord($t_chk1) == 239 && ord($t_chk2) == 187 && ord($t_chk3) == 191 )
{
$line1 = substr( $line1, 3 );
seek( $in, 0, 0 );
print $in $line1;
}
close $in;
}
}
&remove_bom("src/com/umpay/wap20/mobileProxy/MobileProxy.java"
,"src/com/umpay/wap20/security/GeneralKeyPairs.java"
,"src/com/umpay/wap20/security/RSAUtil.java"
,"src/com/umpay/wap/pages/WML.java");
其中remove_bom方法就是处理有问题的文件的方法。
把你的项目中出现问题的文件名称一个一个的放到remove_bom的参数列表中就可以了。ant,BOM,ant,BOM
最后运行这个perl文件。之后再运行ant就可以了。
作为一个SIP Servlet Tutorial,这个文档主要描述了在JavaEE平台下如何开发基于SIP协议的应用服务。当然这个教程也包含了如何将JavaEE技术与SIP应用程序集成。
这个教程主要涉及到的软件有:
1. JavaSE 5.0
2. Glassfish and Sailfin(这是目前为止,我知道的唯一的一个开源的java sip servlet 容器)
3. Netbeans IDE(主要是在sailfin的安装包中有Netbeans的插件,所以使用NB)
4. X-Lite Soft Phone 或者MyFreesipphone
5. Apache Ant
这里就不多介绍SIP协议了,直接进入主题。
熟悉web开发的人基本都知道Http request 和 http Response 两个对象。
对应的,SIP也有对应的对象。
SIP Request
常见SIP Request Action
INVITE 请求初始化一个session
ACK 回应INVITE请求,是(acknowledges的简写)
BYE 请求关闭连接
CANCEL 取消所有未处理的action,但是不释放连接
REGISTER 向服务器注册一个地址,或者说,客户端向服务器发送一个注册请求
什么是SIP Servlets?
SIP Servlet 是一个 基于Java 语言的 server-side 组件,就类似于Java Servlet 一样,只不过SIP Servlet 需要运行在 SIP Servlet 容器中。
而且SIP Servlet主要用来处理SIP请求,而Servlet用来处理HTTP请求。
HTTP Servlet 与 SIP Servlet的不同之处:
1. HTTP Servlet 都会有一个context对象,也就是每个Servlet都有一个上下文的概念。而SIP Servlet没有。
2. HTTP Servlet 通常会返回一个HTML 页面或者某种形式的字符串(比如JSON),而SIP请求通常只是起到连接服务器与客户端的作用。
3. SIP 是一个P2P的协议,所以服务器端同样可以向客户端发送SIP请求。
4. SIP Servlet通常只是扮演一个代理的角色,最终的请求(客户端的请求)会发送到另一个已注册的SIP客户端。而HTTP Servlet会返回给客户端一个HTTP response。
5. SIP协议类似于长连接,但是一个无状态的链接,所以它可以返回个客户端多个相互独立的response,而HTTP是一个无状态的协议,一个Request对一个Response。
6. SIP 请求可以是一个异步的请求。这一点取决于上一个特性。
关于SIP Servlet的annotation。
Annotation 描述
@SipServlet 标示这是一个SIP Servlet
@SipListener 标示这个一个Sip Listener
@SipApplication 用来定义一组SIP Servlets
@SipApplicationKey 为一个SIP请求或者一个SIP session分配一个SipApplicationSession
比如:
@SipServlet
public class MyServlet extends SipServlet{
…
}
@SipApplication 这个注释一般都用在包上。
比如
@SipApplication(name=”MySipApp”)
Package com.example.sip;
而@SipApplicationKey这个注释需要使用在方法上,而且这个方法需要满足以下条件:
1. Public method
2. Static method
3. Return a String
4. 方法的参数必须是SipServletRequest 类型
5. 传入的参数不可变
例如:
@SipApplication(name=”MySipApp”)
Package com.example.sip;
public class MySipApp{
@SipApplicationKey
public static String sessionKey(SipServletRequest request){
Return hash(request.getRequestURI()+getDomain(request.getForm()));
}
}
在一个Sip application中只能有一个SipApplicationKey。
SIP Factory
SIP Factory 是一个Servlet Factory,也就是说所有的SIP请求进入SIP容器后,都要通过SIP Factory来创建一个Servlet实例。所以SIP Factory是整个SIP容器的入口。如果想调用容器中的其他资源,可以通过SIP Factory来调用。而调用的方法包括依赖注入和”查找”两种方式。
看例子:
//通过注释来调用
@Resource
SipFactory sf;
//通过查找的方式
SipFactory sf=(SipFactory)getServletContext().getAttribute(“javax.servlet.sip.SipFactory”);
SIP Session
SIP协议是一个无状态协议,所以一个response只能对应一个request(虽然一个request可以对应多个response)。也就是说多个request之间无法共享数据。
但是SIP Session提供了一种比较便捷的方式,用来存储request之间的共享数据。而这种方式非常类似于HTTP servlet中的Session对象。
但是与HTTP Session不同的是,在SIP应用中还有一个SIP ApplicationSession对象,这个东西很强大,它可以关于整个应用的session信息。
除此之外,还有个SipSessionUtil可以使用。使用方法和SIP Factory类似:
@Resource
SipSessionUtil sessionUtil;
//或者
SipSessionUtil sessionUtil=(SipSessionUtil)getServletContext().getAttribute(“javax.servlet.sip.SipSessionUtil”);
SIP Listeners
SIP application Listeners 就是用来监听SIP相关事件的Java Servlet listeners。它需要实现SIPServletListener接口。同时在其类上标注上Annotation用于简化部署。
比如:
@SipListener
Public class MyListener implements SipServletListener{
…..
}
Back-to-Back User Agent Applications
一个back-to-back user agent(B2BUA)本身就是一个应用程序,同时它还是一个工具,很类似于代理。用于将一个客户端请求,转发给另一个客户端。而javax.servlet.sip.B2buaHelper就是一个实现这种功能的帮助类。
以上内容翻译自SUN的SIP Servlet Tutorial文档。
下面是我自己写的一个简单的sip程序。
package com.ohacker.sip.proxy;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.sip.*;
import javax.servlet.sip.Address;
/**
*
* @author O!Hacker
*/
@javax.servlet.sip.annotation.SipServlet
public class RegistratorServlet extends javax.servlet.sip.SipServlet {
public static ArrayList<Address> CLIENT_LIST=new ArrayList<Address>();
@Override
protected void doInvite(SipServletRequest req) throws ServletException, IOException {
System.err.println("doInvite action: "+ req.getCallId());
Proxy proxy=req.getProxy();
System.err.println(req.getTo().getURI().toString());
proxy.proxyTo(req.getTo().getURI());
}
@Override
protected void doRegister(SipServletRequest req) throws ServletException, IOException {
System.err.println("doRegister action: "+ req.getCallId());
System.err.println("doRegister action: "+ req.getRequestURI());
SipServletResponse resp=null;
Address address=req.getTo();
if(!RegistratorServlet.CLIENT_LIST.contains(address)){
CLIENT_LIST.add(address);
}
System.err.println(CLIENT_LIST.size());
resp=req.createResponse(SipServletResponse.SC_OK);
resp.send();
}
}
Ant 小记
传统的ant 打包的项目需要处理文件和路径。特别是烦人的classpath。Ant内置了很多处理文件和路径的数据类型。比如fileset和path
Fileset可以枚举文件。
比如:
<fileset id=”source.fileset” dir=”src” includes=”**/*.java”/>
其中id是一个引用。其他的操作,可以通过id引用的方式调用它。比如:
<copy todir=”backup”>
<fileset refid=”source.fileset”/>
</copy>
javac
Debugging info
Javac中常用到的选项
Debug=”true” or debug=”false” debu=”true” debuglevel=”lines,vars,source”
Nowarn=”true” verbose=”true” verbose是一个有意思的选项,它会在编译的时候打印出一些编译信息。当然还有classpath。
比如:
<javac destdir="${build.classes.dir}" debug="true" verbose="true" srcdir="src">
<classpath refid="compile.classpath"/>
</javac>
Src也可以用子元素来表示
比如:
<javac destdir="${build.classes.dir}" debug="true" verbose="true">
<classpath refid="compile.classpath"/>
<src path=”src”/>
</javac>
如果源文件分散在多个目录中可以使用引用的方式
比如:
<path id="src.dir">
<pathelement path="src:conf"/>
</path>
<target name="mkdir">
<mkdir dir="${build.classes.dir}"/>
</target>
<target name="compile" depends="mkdir">
<javac destdir="${build.classes.dir}">
<classpath refid="compile.classpath"/>
<src refid="src.dir"/>
</javac>
</target>
还有一种方法,比较土
例子:
<javac destdir="${build.classes.dir}">
<classpath refid="compile.classpath"/>
<src refid="src.dir"/>
<src path=”test”/>
</javac>
但是需要注意的是src指的是一个目录。
在path或者fileset这类标签中常常会遇到类似以”**/*.jsp”这样的匹配模式。下面就讲讲在如何匹配。这种匹配方式好像应该叫做wildcard路径匹配方式。是目前比较常见的3中路径匹配风格之一,(题外话,另两种是mod_rewrite风格和perl 正则风格的路径匹配)
“*”表示一个或多个字符
“?”表示一个字符
“**”表示零个或者多个目录
如果以”/”or”\”结尾,那么就相当于”**”
常见例子:
**/*~ linux 下的备份文件
**/CVS/ cvs元文件
**/.cvsignore cvs文件
**/.svn/ SVN元文件目录
比如在javac中的使用
<javac srcdir=”src” destdir=”build/classes”>
<include name=”org/mama/**/*.java”/>
<exclude name=”org/mama/papa/*.java”/>
</javac>
下面是一个完整的java 项目的build文件
<?xml version="1.0"?>
<project name="java_project" default="archive">
<property file="build.properties"/>
<path id="compile.classpath">
<pathelement location="lib/*.jar"/>
</path>
<path id="src.dir">
<pathelement path="src/java"/>
<pathelement path="src/conf"/>
</path>
<target name="init">
<mkdir dir="${build.classes.dir}"/>
<mkdir dir="dist"/>
</target>
<target name="compile" depends="init">
<javac destdir="${build.classes.dir}">
<classpath refid="compile.classpath"/>
<src refid="src.dir"/>
</javac>
</target>
<target name="archive" depends="compile">
<jar destfile="dist/${project.name}.jar" basedir="build/classes"/>
</target>
<target name="clear" depends="init">
<delete dir="build"/>
<delete dir="dist"/>
</target>
</project>
对应的build.properties文件也很简单
project.name=default
build.classes.dir=build/classes
Glassfish sip server(sailfin) install 安装glassfish sip server
第一步:安装JDK,Ant
第二步:下载sailfin:下载地址
第三步:如果你的机器上正跑着glassfish,先关掉。在你的下载目录下运行:
>java -Xmx256m -jar filename.jar
等解压完后,再运行
>cd sailfin
>ant -f setup.xml
第四步:之后将生成的目录加进环境变量中的Path下。
第五步:在环境变量中加入AS_ADMIN_USER 值为admin
第六步:从新开一个cmd console,运行
asadmin start-domain domain1
第六步:在浏览器中打开http://localhost:4848/
第七步:输入admin/adminadmin
大功告成