Archive for 02月 19th, 2010

perl入门之语法及数据类型

Feb 19 2010 Published by Tony under Perl

这次春节回家,什么资料也没带,刚好机器里也没什么东东,只有之前装的perl,索性翻了翻perl的文档,发现和ruby最相似的语言原来是perl,应该是ruby抄袭的perl。
Perl的语法要求:每一句后最后都要有分号,最后一句可以省略分号。

Perl 的数据类型包括:Scalars,arrays,hashes
Scalar:就是变量
Scalar 值可以是字符串,整形或者浮点型。Perl会自动转型,换句话说,perl是若类型语言。但是如果你要定义一个变量,需要使用my这个关键字。使用起来也极其简单。
Scalar values can be used in various ways:

my $animal = "camel";
    my $answer = 42;
    print $animal;
    print "The animal is $animal\n";
    print "The square of $answer is ", $answer * $answer, "\n";

一般脚本语言都会预定义一些变量。如果你用过ruby或者python,那你一定深有体会。
在perl中也有一些预定义的变量,比如$_就是预定义值。
试一下这两句,你就知道了。

$_="test";
print;

说实话,这种预定义的特性,对于System Administrator来说是一个好用的属性,但是对于Developer来说,真是很痛苦的一个特性。
Array:就是数组

    my @animals = ("camel", "llama", "owl");
    my @numbers = (23, 42, 69);
    my @mixed   = ("camel", 42, 1.23);
 
    print $animals[0];              # prints "camel"
    print $animals[1];              # prints "llama"
  $#array 为最后一个数组元素的下标。例如:
    print $mixed[$#mixed];       # last element, prints 1.23

之前就听说perl的语法及其诡异,但是当我真正用的时候,才发现太诡异了。看下面两句:

if (@animals < 5) { ... }#这一句可以判断@animals中元素的个数。
print @animals;#这一句会打印出@animals中的所有元素。

还有下面这个,和ruby很相似的“范围”语法

  @animals[0,1];                  # gives ("camel", "llama");
    @animals[0..2];                 # gives ("camel", "llama", "owl");
    @animals[1..$#animals];         # gives all except the first element

This is called an “array slice”.
You can do various useful things to lists:

    my @sorted    = sort @animals;
    my @backwards = reverse @numbers;

当然,这里还有很多特殊的数组, 比如@ARGV(the command line arguments to your script) 还有@_(the arguments passed to a subroutine). 后面会有单独的文章介绍。
Hashes
不多说了,一种键值对的数据结构,附带说两句,其实这个数据结构名叫哈希,其实并不是我们熟悉的hash数据结构,因为正统的hash结构其键值之间应该有一种字面意义上的对应关系,特别是应该有一种hash key 生成体制。Perl中的hash没有这个设计。:

    my %fruit_color = ("apple", "red", "banana", "yellow");
You can use whitespace and the => operator to lay them out more nicely:
    my %fruit_color = (
        apple  => "red",
        banana => "yellow",
    );
#To get at hash elements:
    $fruit_color{"apple"};           # gives "red"
#You can get at lists of keys and values with keys() and values().
my @fruits = keys %fruit_colors;
my @colors = values %fruit_colors;

如果要使用hash中的一个元素,则用$符号,如果使用整个hash则使用%符号。例如:

Print $fruit_color{"apple"};           # gives "red"
my @fruits = keys %fruit_colors;

变量作用域:
定义一个变量有两种方式,分别为一下两行:

    my $var = "value";
    $var = "value";

但是,第二行定义的变量将是一个全局变量,而第一行创建的变量是block级别的变量,这一点和JavaScript的语法非常相似。
如下:

    my $x = "foo";
    my $some_condition = 1;
    if ($some_condition) {
        my $y = "bar";
        print $x;           # prints "foo"
        print $y;           # prints "bar"
    }
    print $x;               # prints "foo"
    print $y;               # prints nothing; $y has fallen out of scope

条件语句:
这个与ruby几乎一摸一样:

If与unless
    if ( condition ) {
        ...
    } elsif ( other condition ) {
        ...
    } else {
        ...
    }
unless:
    unless ( condition ) {
        ...
    }

当然也可以写在一行:

print "Yow!" if $zippy;
print "We have no bananas" unless $bananas;

普通循环:

    while ( condition ) {
        ...
    }
    until ( condition ) {
        ...
    }
    print "LA LA LA\n" while 1;          # loops forever

for循环

for ($i = 0; $i <= $max; $i++) {
        ...
    }

foreach循环
看例子:

#Hash:
my %fruit_color=("apple"=>"red","banana"=>"yellow");
foreach my $key(keys %fruit_color){
	print "The value of $key is $fruit_color{$key}","\n";
}
#Array:
my @fruit_arr=("apple","banana","capp","del");
foreach (@fruit_arr){
	print $_,"\n";
}
 
foreach my $i(@fruit_arr){
	print $i,"\n";
}
#还可以写到一行,类似于ruby的语法:
print $_,"\n" foreach (@fruit_arr);
#还可以使用范围:
#比如:
print $list[$_] foreach 0 .. $max;

perl中的变量都是预定义的变量
比如

my $a="";#如果是字符串类型的变量,””等同于false,其他是true
if($a){
print "true";
}else{
print "false";
}
my $a=0;#如果是数字类型的变量,0等同于false,其他是true
if($a){
print "true";
}else{
print "false";
}

my $b;#如果你定义一个变量,没有赋值,那么当你对它操作的时候会自动赋值,如果需要变量为数字型,就赋值为0,如果需要是字符串型,则赋值为””。
$b++;
print($b);

No responses yet

SIP Servlet入门教程及例子

Feb 19 2010 Published by Tony under Java

作为一个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();
        }
    }

    No responses yet

    Ant 小记

    Feb 19 2010 Published by Tony under Java

    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

    No responses yet