用Java实现ARP的收发

Tags: , ,

Jpcap的安装

  • 下载并安装Java Runtime.
  • 下载并安装Winpcap.
  • 下载并安装Jpcap.注意生成的jpcap.jar和jpcap.dll的文件路径。

在Eclipse中配置Jpcap

  • 创建Java Project
  • 将jpcap.jar添加到classpath中。
  • 将jpcap.dll拷贝到eclipse.exe同一目录下。


获得网络接口列表

现在的笔记本都至少有两个以上的网络接口,Jpcap只能针对一个网络接口进行网络包的监听收发,所以第一步是要了解你有哪些网络接口。这是一段现成的代码。

// Obtain the list of network interfaces
NetworkInterface[] devices = JpcapCaptor.getDeviceList();

// for each network interface
for (int i = 0; i < devices.length; i++) { // print out its name and description System.out.println(i + ": " + devices[i].name + "(" + devices[i].description + ")"); // print out its datalink name and description System.out.println(" datalink: " + devices[i].datalink_name + "(" + devices[i].datalink_description + ")"); // print out its MAC address System.out.print(" MAC address:"); for (byte b : devices[i].mac_address) System.out.print(Integer.toHexString(b & 0xff) + ":"); System.out.println(); // print out its IP address, subnet mask and broadcast address for (NetworkInterfaceAddress a : devices[i].addresses) System.out.println(" address:" + a.address + " " + a.subnet + " " + a.broadcast);

访问ARP Table

Java没有办法直接访问Windows下的ARP Table,网上推荐的方法是调用Command Line和SNMP两种。我这里使用的是前者。

final String dosCommand = “arp -a “;
try {
final Process process = Runtime.getRuntime().exec(dosCommand);
BufferedReader br = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String line = null;
/*
* example:192.168.124.255 ff-ff-ff-ff-ff-ff 静态
*/
while ((line = br.readLine()) != null) {
if (line.indexOf(” ” + ip.getHostName() + ” “) > -1) {
StringTokenizer st = new StringTokenizer(line);
st.nextToken();
// return the mac address according to the ip
return st.nextToken();
}
}
} catch (IOException e) {
e.printStackTrace();
}
return null;

针对特定IP发起ARP Request

注意“captor.setFilter(“arp”, true);”的作用是过滤除了ARP之外所有的网络包,用于之后的网络包监听。

int index = Integer.parseInt(args[0]);
InetAddress targetIP = InetAddress.getByName(args[1]);
NetworkInterface device = getDevice(index);
JpcapCaptor captor = JpcapCaptor.openDevice(device, 65535, false,
20);
captor.setFilter(“arp”, true);
JpcapSender sender = captor.getJpcapSenderInstance();
// 进行广播数据报的MAC地址
byte[] broadcast = new byte[] { (byte) 255, (byte) 255, (byte) 255,
(byte) 255, (byte) 255, (byte) 255 };
// 构造REQUEST 类型的ARP的数据包
ARPPacket arp = new ARPPacket();
arp.hardtype = ARPPacket.HARDTYPE_ETHER;
arp.prototype = ARPPacket.PROTOTYPE_IP;
arp.operation = ARPPacket.ARP_REQUEST;
arp.hlen = 6;
arp.plen = 4;
// 源MAC地址
arp.sender_hardaddr = device.mac_address;
// 源IP地址
arp.sender_protoaddr = device.addresses[0].address.getAddress();
// 目地MAC地址:广播地址全为1(二进制)
arp.target_hardaddr = broadcast;
// 目地IP地址
arp.target_protoaddr = targetIP.getAddress();
// 构造以太网头部
EthernetPacket ether = new EthernetPacket();
ether.frametype = EthernetPacket.ETHERTYPE_ARP;
ether.src_mac = device.mac_address;
ether.dst_mac = broadcast;
// ARP数据包加上以网关头部
arp.datalink = ether;
// 向局域网广播ARP请求数据报
sender.sendPacket(arp);

监听ARP

Jpacap处理网络包的形式有好几种,具体可以参考官网的Tutorial.我这里使用的getPacket使用的blocking模式,所以不会同步处理包监听。
这段代码最后会判断返回的mac是否是本地缓存的,如果不是则可以认为是ARP欺骗。

while (true) {
ARPPacket packet = (ARPPacket) captor.getPacket();
if (packet != null && packet.operation == ARPPacket.ARP_REPLY) {
Inet4Address ip = (Inet4Address) packet
.getSenderProtocolAddress();
if (ip.equals(targetIP)) {
String localMac = ARP.getMacByIP(ip);
if (localMac != null ){
localMac = localMac.replaceAll(“-”, “:”);
}
if (localMac.equals(packet.getSenderHardwareAddress())) {
//Cheat
System.exit(1);
}
}
}
}

问题总结

Can’t load IA 32-bit .dll on a AMD 64-bit platform
Jpcap目前不支持64位,如果你Eclipse运行的vm是64位的,就会报这个错,下载一个32位的JRE或者JDK就可以了。


java.lang.UnsatisfiedLinkError: no jpcap in java.library.path
这是classpath中找不到DLL文件,解决的办法很多。我的做法是把jpcap.dll拷贝到eclipse.exe的文件夹下。

参考链接

WinPcap
Jpcap Download
Jpcap How to install
Jpcap 在myeclipse下的安装
JPCAP——Java中的数据链路层控制(libpcap)

 

Liferay 6.0.5的定制

安装好了Liferay自然要玩耍一下。不过不管怎么玩都是人家的东西,要最后完成成自己需要的功能和样子,还需要自己去作二次开发定制。关于这方面的内容网上没有比较清晰的思路可以参考,于是自己写了一些方面,给以后留一些参考。

删除sevencogs
默认的安装包中提供了一个叫做sevencogs的示例站点。由于使用了Hooks Plugin,会和原装的liferay表现有所不同,所以如果你自己要做定制的话,最好把他们先删除。
 
rm -rf liferay-portal-6.0.5/tomcat-6.0.26/webapps/sevencogs*

配置Portlets
Liferay除了核心包中提供了很多实用的Portlet之外,还在liferay-portal-6.0.5/tomcat-6.0.26/webapps/下默认部署了很多强大的Portlets。具体的介绍可以参考下面这个页面。
http://www.liferay.com/zh/community/wiki/-/wiki/Main/Liferay+Portlets
个人的建议是不需要的话先删除,反正之后需要了也可以再添加回来。这样服务器启动也可以迅速不少。

配置MYSQL
默认的Liferay使用的嵌入式数据库HSQL,不过你启动的时候Liferay也会提醒你不要太当真,真要用了一定要修改数据库配置。
首先,在mysql中创建数据库。

create database lportal character set utf8;

然后修改下面这个文件(如果没有就创建)。

liferay-portal-6.0.5/tomcat-6.0.26/webapps/ROOT/WEB-INF/classes/portal-ext.properties

在其中添加一下配置(以MYSQL为例)

jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.url=jdbc:mysql://localhost/lportal?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.default.username=
jdbc.default.password=

之后Liferay启动的时候就会自动读取这个配置文件以对应的数据库配置启动了。如果数据表没有创建过还会贴心的帮你创建并且导入基础数据。
具体各种数据库配置示例可以访问下面的链接。
http://www.liferay.com/zh/community/wiki/-/wiki/Main/Database+Configuration;jsessionid=F70539C702464D413394D1A66428E3EC.node-1

自定义布局和主题
Liferay的外观修改主要分成两个部分Layout和Theme.
Layout指的是布局。页面上每个Portal的大小和相对位置都是通过Layout进行定义的。
Theme指的是主题。页面的图片,HTML风格都是由Theme来决定的。

创建Layout
在最新的Liferay IDE 1.1.0中可以方便的创建Layout Plugin来对这个部分进行定制。
1)创建项目
File ->New Liferay Plug-in Project -> Plug-in Type: Layout.
IDE会创建一个“项目名称-layoutpl”的项目。
2)部署项目
Liferay Server-> Add or Remove -> 选择该项目。启动Liferay -> Server
部署的时候会把项目文件拷贝到liferay-portal-6.0.5/tomcat-6.0.26/webapps/下,然后会被Liferay侦测到,加载到系统中。
3)选择新布局
用管理员帐号登录后,可以通过 Manage -> Page Layout 选择你新开发的布局。

创建Theme
Liferay IDE 1.1.0中同样可以方便的创建Layout Theme来对这个部分进行定制。
1)创建项目
File ->New Liferay Plug-in Project -> Plug-in Type: Layout.
IDE会创建一个“项目名称-theme”的项目。
2)部署项目
Liferay Server-> Add or Remove -> 选择该项目。启动Liferay -> Server
部署的时候会把项目文件拷贝到liferay-portal-6.0.5/tomcat-6.0.26/webapps/下,然后会被Liferay侦测到,加载到系统中。
3)选择新布局
用管理员帐号登录后,可以通过 Manage -> Page -> Look and Feel 选择你新开发的主题。
需要注意的是Liferay支持每个页面配置不同的主题。

创建Portlet
这是大家讨论最多的部分。这边就不细说了。
唯一值得一提的是Liferay开发Portlet支持Plug-in和Ext 两种开发模式。具体的好坏我会以后有机会单独叙述。

为控制面板创建Portlet
除了给每个页面(Page)配置Porlet之外,经常也会有需要为个人控制面板添加Portlet功能。例如我的喜好,我的兴趣,我的足迹之类的功能。
Liferay中控制面板也可以视为一个特殊的页面,左边的菜单栏是一个特殊的Portlet,它会把所有需要显示在控制面板中的Portlet罗列出来。右边则是Portlet点选之后显示的内容。
一个Portlet如果需要显示在控制面板中,需要在/WEB-INF/liferay-portlet.xml中为Portlet添加如下内容

<control-panel-entry-category>my</control-panel-entry-category>
<control-panel-entry-weight>14</control-panel-entry-weight>

control-panel-entry-category指的菜单项的分类,包括’my’, ‘content’, ‘portal’ and ‘server’四种。control-panel-entry-weight指的是菜单项在该分类中的相对位置。
需要注意的是可能会出现常见问题一中的错误。

常见问题
1)Error on line 13 of document : The content of element type “portlet” must match
liferay-portlet.xml对顺序也有一定的要求。最简单的方法就是参考ROOT下的liferay-portlet.xml依样画葫芦,肯定不会错。

参考资料
Liferay THemes.pdf
Liferay Admin Guide

 

liferay 6.0.5 开发环境的搭建

最近在玩liferay,非常赞的一个门户搭建工具。不仅提供了开发工具包,和服务器的捆绑包,论坛和文档的质量也都非常高,最重要地是还有非常多的插件支持。绝对是开发Portlet上佳选择。

记性不好,记下来,说不定啥时候就要用到了。

前提

安装Java JDK 1.5+.

1)下载安装文件

liferay-portal-tomcat-6.0.5.zip捆绑了liferay和tomcat,让你不用省心不少的体贴服务。

liferay-plugins-sdk-6.0.5.zip用于开发liferay plugin的SDK。

liferay-ide-eclipse-updatesite-….zipEclipse 插件,功能强大的liferay plugin开发工具包。

2)在本地解压缩
我个人喜欢把所有相关的安装文件都放在一个目录下。

mkdir liferay
unzip liferay-portal-tomcat-6.0.5.zip
unzip liferay-plugins-sdk-6.0.5.zip

3)开发工具包的安装
使用的是Eclipse 3.5,低版本的请相应查找安装方法。
3.1)安装liferay插件
Install New Software -> Add -> Archive ( 选择liferay-ide-eclipse-updatesite-1.1.0.zip)->逐步安装。
3.2)设置liferay SDK
Preference -> Liferay -> Installed SDKs -> Add (选择liferay-plugins-sdk-6.0.5.zip的解压缩文件夹位置)。
3.3)设置liferay服务器
Preference -> Server -> Runtime -> Add -> Server Type ( Liferay v6.0) -> 选择liferay-portal-tomcat-6.0.5.zip皆压缩位置。
3.4)重启一下。
开发工具包就安装好了。感谢Eclipse强大的插件架构和liferay细心的服务。

4)测试使用
1)添加服务器
在Liferay的Perspective下,Servers -> New Server -> Liferay v6.0.
2)运行服务器
Liferay v6.0 -> Start
3)访问http://localhost:8080/
4)用test@liferay.com/test登录。

使用心得
Liferay Plugin Project 创建的时候会执行一些ant脚本。所以如果你需要使用版本管理的时候,个人建议不要check
in项目控制文件(.project, .classpath),这样你的同伴检出的时候可以通过创建新项目完成这些脚本的执行。避免不同步的现象发生。

参考文章
LifeRay安装配置开发环境全过程(一)
Eclipse – Liferay Wiki
【原创】Liferay Portal二次开发指南(总览)
Liferay Portal 6学习笔记3:Liferay IDE的安装使用

 

在Google App Engine for Java上使用JSTL

想要在Google App Engine上部署一个Google Apps的Sample Code — Event Publisher,结果问题连连.
一方面是各种dependencies的问题,这个只能怪自己粗心. 另外一个主要的问题就是Event Publisher使用了JSTL而Google App Engine For Java对JSTL的支持有些特别.特地记录一下提醒自己.
主要问题
服务器报错500.

java.lang.AbstractMethodError: javax.servlet.jsp.PageContext.getELContext()Ljavax/el/ELContext;

原因分析
这个错误信息还是非常有名的.Google一下发现大致的原因是getELConext()这个方法是JSTL1.2之后才支持的方法.需要Servlet API 2.5以及JSP API 2.1的支持.具体产生错误的地方包括下面这三个地方.

注意事项一:注意使用的servlet标准版本
web.xml中会标注目前支持的servlet API版本.

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
...
</web-app>

如果你使用了2.4的话,那可能会抱错NoSuchMethodError.本文的错误和这个无关,只是总结一个可能影响JSTL使用的一个因素.

注意事项二:添加jsp header
GAE for Java需要用到下面的jsp header.如果你的jstl在GAE for Java中不工作,那么可以尝试添加下面的语句.

<%@page isELIgnored="false" %>

注意事项三:jstl.jar和standard.jar
Event Publisher需要使用第三方的jstl.jar和standard.jar,所以我在GAE for Java项目中也引入了这两个类库.
但是其实GAE for Java已经提供了对JSTL的支持.而且它的实现和标准的jstl略有差异(标准的jstl.jar不认注意事项二中的tag).所以千万不要画蛇添足自己引入这两个jar文件.

OK,还有什么问题.请留言给我吧.

 

Ubuntu下的LDAP的搭建与Spring LDAP编程

最近要装LDAP.
不得不感叹wiki.ubuntu.org.cn真是非常的强大,要啥有啥。
按照上面的步骤,OpenLDAP Server就很快搭好了,
自动搜索到了我的本地域名,
设置admin密码
如丝般柔顺。。。
(其实也不尽然,我家的服务器按照上面的步骤,竟然没有最重要的slapd.conf,
郁闷死我了)
 
然后就是找一个Administrator
网上的资源纷繁复杂,让我找了好半天
对LDAP的完全不了解-,-,主要是对Dn,Cn的混淆,
让我尝试了很多客户端都放弃了。。。。
(其实Dn=Base+Cn,皑皑,后来才知道)
最后选择了phpldapadmin,简洁,明了,
主要是在网上搜到了可以直接设置cn,,,
第一个让我登录成功的Administrator….感动了
sudo apt-get install phpldapadmin
 
稍微玩了一把LDAP
感觉就是针对公司机构,人事特别设计的一颗对象树。
Root就是Base Domain
地下可以设置人员CN,机构OU和其他各种对象。
Email Account,User Account,一应俱全。
最主要的是还可以自己Customize,复选多种objectclass来订制节点属性。
其实用处不大,可能主要是已经应用非常广泛了吧。
 
OK,玩好了最大的用处当然是集成到我的应用中。
用过了Spring以后就难以割舍,集成太方便了,inject就有了。
Java Main写的Demo Code可以很方便的intergrate到其他web application中。
所以Spring LDAP当然就是我的不二选择。
 
说实话Spring LDAP非常的贴心,
就怕你不会用,基本的用法完全类似JDBCTemplate(当然还有Triditional的用法,没来得及看)
三下五除二就搞定了(当然除了可怕的dn,cn)….
public class UserDaoLdapImpl {
    private LdapTemplate ldapTemplate;
    public LdapTemplate getLdapTemplate() {
        return ldapTemplate;
    }
    public void setLdapTemplate(LdapTemplate ldapTemplate) {
        this.ldapTemplate = ldapTemplate;
    }
    public List GetAllPersonNames(){
        return this.ldapTemplate.search("","(&(objectclass=person)(cn=*ny*))",
                new AttributesMapper(){
                    public Object mapFromAttributes(Attributes attrs)
                        throws NamingException{
                        return attrs.get("cn").get();
                    }
        });
    }
}
<beans>
    <bean id="contextSource"
        class="org.springframework.ldap.core.support.LdapContextSource">
        <property name="url" value="ldap://XXXX:389" />
        <property name="base" value="dc=xiluo2,dc=com" />
        <property name="userDn" value="cn=admin,dc=xiluo2,dc=com" />
        <property name="password" value="xiuxiu" />
    </bean>
    <bean id="ldapTemplate"
        class="org.springframework.ldap.core.LdapTemplate">
        <constructor-arg ref="contextSource" />
    </bean>
    <bean id="userDao" class="hellospringldap.UserDaoLdapImpl">
        <property name="ldapTemplate">
            <ref bean="ldapTemplate" />
        </property>
    </bean>
</beans>
 
这里还要赞美以下Netbeans
直接建立Web Application就可以支持Spring, Hibernate(虽然没用上)
然后方便的添加Spring LDAP的Jar和beans申明,OK,搞定了。
 
最后就是LDAP和Call Manager的intergration.
1)System->LDAP System,选择类型OpenLDAP
2)System->LDAP Directory,设置Base,IP,port,Username,password(注意cn,dn…)
OK,搞定,Corporation Directory就可以用了。
 

 

一次Spring Refactoring实战

用CXF作了一个调用AXL Web Services的Demo,
现在需要把它放到我的Web Application里面,最快的方法当然是Spring Inject.
于是很bt的try了一把spring Refactoring.
 
说起来其实CXF本身对Spring的支持就非常的好。
基于Spring扩展的cxf.xml,基于Spring的FactoryBean和Client.
可要命的是AXL的Web Services并不标准。
一个定制HTTP认证头的Interceptor,一个定制的TrustManager,把美观的cxf.xml弄得一无是处。
加上之前CXF菜鸟,只是照葫芦画瓢,这些因为都导致了这次refactoring的艰辛。。。(-,-,铺陈铺陈)
 
原始的Code

public class AXLClient
   public static void main(String[] args) throws Exception {
        URL wsdlUrl = AXLClient.class.getResource("AXLAPI.wsdl");
        QName SERVICE_NAME = new QName("http://www.cisco.com/AXLAPIService/", "AXLAPIService");
        Service service = Service.create(wsdlUrl, SERVICE_NAME);
        AXLPort port = service.getPort(AXLPort.class);
        BindingProvider provider = (BindingProvider) port;
        Map<String, Object> reqContext = provider.getRequestContext();
        reqContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://IPAddress:8443/axl/");
        Client client = ClientProxy.getClient(port);
        client.getOutInterceptors().add(new AXLInterceptor());
        //set SSL
        HTTPConduit http = (HTTPConduit) client.getConduit();
        TLSClientParameters  tls = new TLSClientParameters();
        tls.setDisableCNCheck(true);
        tls.setTrustManagers(new TrustManager[]{new MyTrustManager()});
        http.setTlsClientParameters(tls);
        HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
        httpClientPolicy.setAllowChunking(false);
        http.setClient(httpClientPolicy);
        GetPhoneReq req = new GetPhoneReq();
        req.setPhoneName("SEPXXXXXXXXX");
        System.out.println(port.getPhone(req));
    }
}

step 1
将"SEPXXXXXXXXX"替换为String ID
将public static void main() 修改为public voice getPhone(String ID);
然后Spring就可以注入了
<bean id="AXLClient" class="…"/>
娃哈哈,最后技术含量的就是这步了。。。
 
step 2
Spring的真髓就是IoC,"No new,All is injected"
于是有了这样四个Attributes
 private AbstractPhaseInterceptor<Message> authInterceptor;
 private TrustManager[] trustManagers;
 private Resource axlWsdl;
 private AXLPort axlPort;
 <bean id="axlService" class="com.cisco.twitter.axl.AXLServiceImpl">
  <property name="axlPort" ref="axlPort"/>
  <property name="axlWsdl"  value="classpath:AXLAPI.wsdl"/>
  <property name="authInterceptor"  ref="authInterceptor"/>
  <property name="trustManagers" >
   <list>
    <bean id="defaultTrustManager" class="com.cisco.twitter.axl.DefaultTrustManager"/>
   </list>
  </constructor-arg>
 </bean>
其中需要提到的是Spring的Resource真的很好用,直接classpath:XXX就可以调用我需要的资源文件了,方便一个字。
 
Step 3
其实这步应该水到渠成的。
CXF本来就支持Spring的配置集成。形如:
<bean id="axlPort" class="com.cisco.twitter.axl.model.AXLPort"
   factory-bean="axlClientFactory" factory-method="create"/>
   
 <bean id="axlClientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
   <property name="serviceClass" value="com.cisco.twitter.axl.model.AXLPort"/>
   <property name="address" value="https://100.100.3.71:8443/axl/"/>
 </bean>
通过JaxWsProxyFactoryBean这个工厂类,可以方便的生成Client类。
可是由于我一开始的实现是胡乱拼凑的,所以根本不知道这里Factory,Client最硬的是我Code中的哪个部分。
所以绕了很多弯路。
最后发现“Client client = ClientProxy.getClient(port);”以上的code都可以通过上面的Code取代。
 
Step5
//set SSL
HTTPConduit http = (HTTPConduit) client.getConduit();

TLSClientParameters  tls = new TLSClientParameters();
tls.setDisableCNCheck(true);
tls.setTrustManagers(new TrustManager[]{new MyTrustManager()});
http.setTlsClientParameters(tls);
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setAllowChunking(false);
http.setClient(httpClientPolicy);
 
Spring中的实例默认是Singleton的。
以上的Code是对Request的定制,只需要执行一次就可以了。
于是可以把这段code放在构造函数中。
相应的修改是把Spring配置中的property修改成constructor-arg
因为构造函数需要其中的属性。
 
Step6
建立接口,好习惯,要保持。
public interface AXLService {
 public String getDeviceIdByPhoneNumber(String phoneNumber);
}
 
最后的结果

public interface AXLService {
 /**
  *
  * @param phoneNumber
  * @return
  */
 public String getDeviceIdByPhoneNumber(String phoneNumber);
}
public class AXLServiceImpl implements AXLService {
 private AbstractPhaseInterceptor<Message> authInterceptor;
 private TrustManager[] trustManagers;
 private Resource axlWsdl;
 private AXLPort axlPort;
    protected final Log log = LogFactory.getLog(getClass());
 
 public AXLServiceImpl(AXLPort axlPort,Resource axlWsdl,
   AbstractPhaseInterceptor<Message> authInterceptor,
   TrustManager[] trustManagers){
  this.axlPort = axlPort;
  this.axlWsdl = axlWsdl;
  this.authInterceptor = authInterceptor;
  this.trustManagers = trustManagers;
  
  Client client = ClientProxy.getClient(axlPort);
        //set the auth string
        client.getOutInterceptors().add(this.authInterceptor);
        //set the own trustManager
        HTTPConduit http = (HTTPConduit) client.getConduit();
        TLSClientParameters  tls = new TLSClientParameters();
        tls.setDisableCNCheck(true);
        tls.setTrustManagers(this.trustManagers);
        http.setTlsClientParameters(tls);
        HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
        //set the content-length
        httpClientPolicy.setAllowChunking(false);
        http.setClient(httpClientPolicy);
  
 }
    /**
     * @param args the command line arguments
     */
    public String getDeviceIdByPhoneNumber (String phoneNumber) {
        ExecuteSQLQueryReq req = new ExecuteSQLQueryReq();
        req.setSql("select d.name from device d,devicenumplanmap m, numplan n "+
          "where d.pkid = m.fkdevice and m.fknumplan=n.pkid and n.dnorpattern=’"+
          phoneNumber+"’");
        try{
         ExecuteSQLQueryRes result = axlPort.executeSQLQuery(req);
         //the only user of the line
         if (result.getReturn().getRow().size() == 1 ){
          return ((Row)result.getReturn().getRow().get(0)).getName();
         }
         return null;
        }
        catch(SOAPFaultException e){
         log.warn("Failed to connect Call Manager." + e);
         return null;
        }
    }
}
<bean id="authInterceptor" class="com.cisco.twitter.axl.AuthInterceptor">
  <property name="ccmuser" value="ccmadmin"/>
  <property name="password" value="ipcbuadmin"/>
 </bean>
 <bean id="axlPort" class="com.cisco.twitter.axl.model.AXLPort"
   factory-bean="axlClientFactory" factory-method="create"/>
   
 <bean id="axlClientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
   <property name="serviceClass" value="com.cisco.twitter.axl.model.AXLPort"/>
   <property name="address" value="https://XXXX:8443/axl/"/>
 </bean>
 
 <bean id="axlService" class="com.cisco.twitter.axl.AXLServiceImpl">
  <constructor-arg index="0" ref="axlPort"/>
  <constructor-arg index="1" value="classpath:AXLAPI.wsdl"/>
  <constructor-arg index="2" ref="authInterceptor"/>
  <constructor-arg index="3">
   <list>
    <bean id="defaultTrustManager" class="com.cisco.twitter.axl.DefaultTrustManager"/>
   </list>
  </constructor-arg>
 </bean>


 

 

Ubuntu 7.10下JDK的手动升级

Tags: ,
Ubuntu 7.10源里面的JDK最新只有6u03.
可恶的CXF需要最新的MTOM只有JDK6u10以后才支持。
没办法,只好手动升级。
 
查看了一下当前的系统变量
JAVA_HOME指向的是/usr/lib/jvm/java-6-sun/
/usr/bin/java指向的是/etc/alternatives/….
update-alternative中java指向的是/usr/lib/jvm/java-6-sun/
/usr/lib/jvm/java-6-sun指向的是/usr/lib/jvm/java-6-sun-1.6.0.03/
看起来修改/usr/lib/jvm/java-6-sun就万事大吉了@@
 
去Sun上下载JDK的bin
压缩,
把解压文件放在/usr/lib/jvm/下
重建/usr/lib/jvm/java-6-sun的link指向新的目录
 
OK.似乎一切都work了,不知道还有什么系统变量之类的没有修改,上帝保佑我吧

 

AXL vs JTAPI

Tags: , , ,
从Call Manager Programming Guide里下了好几篇。
感觉下来AXL和JTAPI属于比较实用的两种接口。
说到底也就是后台那上百张表的事情。
不过从目前所知两者还是有一些区别。
 
AXL的精华就是ExecuteSQLQuery和ExecuteSQLUpdate。
其他都是基于这两个接口的具体应用。
通过Web Services将这些接口暴露出来。
客户端可以通过WSDL实现客户端,与Call Manager实现通讯进行查询和数据操作。
 
JTAPI是Sun推出的Call Control的API。
Call Manager实现了它,并且针对Call Manager的功能进行了扩展。
它的主要主要实现方式是Event,Observer.
通过实现JTAPI的接口,为Terminal,Address添加Observer来监控各种数据信息。
 
AXL的实现方式是目前流行的Web Services,
但是实现的比较糟糕。。。ExecuteSQLQuery,ExecuteSQLUpdate两个根本没办法直接用,骂人了。
 
JTAPI是Sun的标准,不过据说本身比较乱。
通过/plugins/jtapi.jar来实现编程调用。
 
感觉上AXL针对的是比较静态的配置信息。
JTAPI可以通过Event更好的获取动态设备信息。
 
-。-随便说说,等回去了玩玩看JTAPI的Demo.

 

关于tomcat集群的想法

一直有兴趣的就是企业级应用,面对高并发,高性能要求的应用开发.可是以前都分不太清集群和负载均衡之间的联系和区别.
最近作了一些实践,对它们的概念有了一个比较清楚地认识.
负载均衡:主要focus在多台服务器之间的控制,针对的是面对高并发的情况如何分摊请求,着重的是session — server的sticky.
集群     :主要focus在多台服务器之间的状态同步,针对的是多台服务器之间状态同步,着重的是session状态.
 
动手配置了一把基于tomcat的负载均衡,本来还想动手配置一把基于tomcat的集群,但是读了官网文档以后还是放弃了这个打算.
 
主要原因很简单,tomcat集群的本质就是基于多播的多台服务器之间的session拷贝.按照官网介绍,这样的解决方案只能适用于比较小的cluster,而对于比较大的cluster,session同步以及session sticky failure带来的问题可能造成集群很大的问题,所以不建议使用.
 
当然另外一个原因是一直很迷的memcached,基于libevent的缓存服务器实现.网上对它的测试报告很多,性能非常的好.通过它可以非常好地实现SNA(Share nothing architecture), 很多大型网站都是用它来解决session同步,缓存的问题.当然其中也有同步延时之类的问题.但是相对于cluster,这样的多线程同步之间的问题更加清晰可见,网上也有很多讨论可以参考.希望有机会能做一个压力测试.
 
参考:
 
 
 
 

 

基于Ubuntu的Tomcat 负载均衡配置

Ubuntu:7.10
Tomcat:6.0.16
apache:2.2
JK       :1.2.26
 
Tomcat的负载均衡已经不是什么新鲜话题了.
主要的问题是Ubuntu下的Apache2.2,JK的安装文件结构略有不同,导致一般基于Linux的JK安装教程不是完全通用.
 
文件安装
Ubuntu就是这么得轻松暇意
sudo apt-get install apache2 libapache2-mod-jk
 
文件结构
libapache2-mod-jk的配置文件在/etc/libapache2-mod-jk/work.properties
apache2的配置文件都在/etc/apache2下.
和一般的配置不同的是/etc/apache2/httpd.conf是空的.
ubuntu下的配置文件是通过/etc/apache2/apache2.conf以及两个文件夹mods-enabled,sites-enabled来实现的
apache2.conf默认如下配置:
 
Include /etc/apache2/conf.d/
Include /etc/apache2/sites-enabled/
Include /etc/apache2/mods-enabled/*.load
Include /etc/apache2/mods-enabled/*.conf
 
Tomcat的配置
修改{CATALINA_HOME}/conf/server.xml,增加红色部分内容.注意"worker1"需要和apache2中的worker.properties标示一致.
<Engine name="Standalone" defaultHost="localhost" jvmRoute="worker1"
 
Apache2的配置
安装libapache2-mod-jk的时候已经自动添加了/etc/apache2/mods-enabled/jk.load,包含了Load Module的部分配置.
然后在apache2.conf中增加如下配置(按照我的猜测,更加标准的做法是在/etc/apache2/mods-enabled/下创建jk.conf进行配置)
JkWorkerFile /etc/libapache2-mod-jk/worker.properties
JkMount /*.jsp router
JkMount /*/servlet router
JkMount /jkmanager/* jkstatus #用于监测Load Balancer状态
 
然后修改/etc/libapache2-mod-jk/worker.properties

worker.list=router 
worker.worker1.type=ajp13 
worker.worker1.host=localhost 
worker.worker1.port=8009 
worker.worker1.lbfactor=1  
 
worker.worker2.type=ajp13 
worker.worker2.host=localhost 
worker.worker2.port=8010 
worker.worker2.lbfactor=1  
 
worker.router.type=lb 
worker.router.balance_workers=worker1,worker2 

 
#用于监测Load Balancer状态
worker.list=jkstatus 
worker.jkstatus.type=status
 
运行
启动Tomcat
sudo {CATALINA_HOME}/bin/catalina.sh start
启动Apache
sudo /etc/init.d/apache2 restart
 
另外关键的是JK1.2默认的是Session Sticky,如果需要修改清参考reference.

 

无觅相关文章插件,快速提升流量