jboss jms配置

 

参见文档:http://www.jboss.org/file-access/default/members/jbossmessaging/freezone/docs/userguide-1.4.2.GA/html/index.html
http://www.jboss.org/file-access/default/members/jbossas/freezone/docs/Server_Configuration_Guide/4/html/index.html

O'Relly 中 EJB3中的:

Almost anything that can be done with the pub/sub model can be done with point-to-point, and vice versa. An analogy can be drawn to developers' programming language preferences. In theory, any application that can be written with Pascal can also be written with C. Anything that can be written in C++ can also be written in Java. In some cases, it comes down to a matter of preference, or which model you are already familiar with.

In most cases, the decision about which model to use depends on which model is a better fit for the application. With pub/sub, any number of subscribers can be listening on a topic, and all of them will receive copies of the same message. The publisher may not care if everybody is listening, or even if nobody is listening. For example, consider a publisher that broadcasts stock quotes. If any particular subscriber is not currently connected and misses out on a great quote, the publisher is not concerned. In contrast, a point-to-point session is likely to be intended for a one-on-one conversation with a specific application at the other end. In this scenario, every message really matters. The range and variety of the data the messages represent can be a factor as well. Using pub/sub, messages are dispatched to the consumers based on filtering that is provided through the use of specific topics. Even when messaging is being used to establish a one-on-one conversation with another known application, it can be advantageous to use pub/sub with multiple topics to segregate different kinds of messages. Each kind of message can be dealt with separately through its own unique consumer and onMessage( ) listener.

Point-to-point is more convenient when you want a particular receiver to process a given message once. This is perhaps the most critical difference between the two models: p2p guarantees that only one consumer processes each message. This ability is extremely important when messages need to be processed separately but in tandem.

publish/subscriber 是推送,当时没接到的就再接不到了(durable除外)
p2p是poll, 总是保证有一个接收者接收到了。

配置topic,以-service.xml结尾的xml文件或直接在%jboss_home%\server\default\deploy\jms\jbossmq-destinations-service.xml中配置。
<?xml version="1.0" encoding="UTF-8"?>
<server>
  <!-- Destination without a configured SecurityManager or without a
       a SecurityConf will default to role guest with read=true, write=true,
       create=false.
  -->
  <mbean code="org.jboss.mq.server.jmx.Topic"
     name="jboss.mq.destination:service=Topic,name=myTestTopic">
    <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
    <depends optional-attribute-name="SecurityManager">jboss.mq:service=SecurityManager</depends>         
    <attribute name="JNDIName">jms/test/testT</attribute>   <!-- 如果这里没配置,则默认的是topic/myTestTopic(对于queue则是queue/queue名) -->
  </mbean>   
</server>

ConnectionFactory的配置:%jboss_home%\server\default\deploy\jms\uil2-service.xml
jboss默认的factory分别是
Queue:QueueConnectionFactory
Topic:TopicConnectionFactory
像上面的myTestTopic则应该在TopicConnectionFactory中查找。
关于自定义factory还没弄明白!

下面引用自http://blog.csdn.net/jiulong/archive/2006/08/21/1101385.aspx

在jboss 4中,如果一个appserver A中的消息驱动bean需要访问另外一个appserver B中的消息队列,需要对A及其bean部署文件做相应的配置;对于消息服务器B无需做改动。
对A大致要做3件事情。
1、修改jboss安装目录的jboss-4.0.2\server\default\deploy\jms的jms-ds.xml文件,用红色部分替换掉灰色部分。这里实际上是重新配置了我们如何去访问远程jndi服务器绑定的对象。
 
<?xml version="1.0" encoding="UTF-8"?>
 
<connection-factories>
 
<!-- ==================================================================== -->
<!-- JMS Stuff                                                            -->
<!-- ==================================================================== -->
 
<!-- The JMS provider loader -->
<mbean code="org.jboss.jms.jndi.JMSProviderLoader"
         name="jboss.mq:service=JMSProviderLoader,name=JMSProvider">
    <attribute name="ProviderName">DefaultJMSProvider</attribute>
    <attribute name="ProviderAdapterClass">
      org.jboss.jms.jndi.JNDIProviderAdapter
    </attribute>
    <!-- The combined connection factory -->
    <attribute name="FactoryRef">java:/XAConnectionFactory</attribute>
    <!-- The queue connection factory -->
    <attribute name="QueueFactoryRef">java:/XAConnectionFactory</attribute>
    <!-- The topic factory -->
    <attribute name="TopicFactoryRef">java:/XAConnectionFactory</attribute>
    <!-- Uncomment to use HAJNDI to access JMS
    <attribute name="Properties">
       java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
       java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
       java.naming.provider.url=localhost:1100
    </attribute>
    -->
</mbean>
 
 
 <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
         name="jboss.mq:service=JMSProviderLoader,name=RemoteJMSProvider,server=192.168.0.92">
    <attribute name="ProviderName">QueuehostJMSProvider</attribute>
    <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
    <!-- The queue connection factory -->
    <attribute name="QueueFactoryRef">XAConnectionFactory</attribute>
    <!-- The topic factory -->
    <attribute name="TopicFactoryRef">XAConnectionFactory</attribute>
    <!-- Connect to JNDI on the host "queuehost" port 1099-->
    <attribute name="Properties">
       java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
       java.naming.factory.url.pkgs=org.jnp.interfaces
       java.naming.provider.url=192.168.0.92:1099
    </attribute>
</mbean>
 
 
<!-- The server session pool for Message Driven Beans -->
<mbean code="org.jboss.jms.asf.ServerSessionPoolLoader"
         name="jboss.mq:service=ServerSessionPoolMBean,name=StdJMSPool">
    <depends optional-attribute-name="XidFactory">jboss:service=XidFactory</depends>
    <attribute name="PoolName">StdJMSPool</attribute>
    <attribute name="PoolFactoryClass">
      org.jboss.jms.asf.StdServerSessionPoolFactory
    </attribute>
</mbean>
 
<!-- JMS XA Resource adapter, use this to get transacted JMS in beans -->
<tx-connection-factory>
    <jndi-name>JmsXA</jndi-name>
    <xa-transaction/>
    <rar-name>jms-ra.rar</rar-name>
    <connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>
    <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
    <config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/DefaultJMSProvider</config-property>
    <max-pool-size>20</max-pool-size>
    <security-domain-and-application>JmsXARealm</security-domain-and-application>
</tx-connection-factory>
 
</connection-factories>
 
2、在消息驱动Bean所在的ejb.jar文件的jboss.xml部署描述符文件中加入如下代码.
 
<jboss>
 
   <invoker-proxy-bindings>
      <invoker-proxy-binding>
         <name>lottery-mdb-invoker</name>
         <invoker-mbean>does-not-matter</invoker-mbean>
         <proxy-factory>org.jboss.ejb.plugins.jms.JMSContainerInvoker</proxy-factory>
         <proxy-factory-config>
            <JMSProviderAdapterJNDI>QueuehostJMSProvider</JMSProviderAdapterJNDI>
            <ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>
            <MinimumSize>1</MinimumSize>
            <KeepAliveMillis>30000</KeepAliveMillis>
            <MaximumSize>15</MaximumSize>
            <MaxMessages>1</MaxMessages>
            <MDBConfig>
               <ReconnectIntervalSec>10</ReconnectIntervalSec>
               <DLQConfig>
                  <DestinationQueue>queue/DLQ</DestinationQueue>
                  <MaxTimesRedelivered>10</MaxTimesRedelivered>
                  <TimeToLive>0</TimeToLive>
               </DLQConfig>
            </MDBConfig>
         </proxy-factory-config>
      </invoker-proxy-binding>
   </invoker-proxy-bindings>
 
</jboss>
 
 
3、在mdbean配置部分加上如下红色部分语句。
<invoker-proxy-binding-name>lottery-mdb-invoker</invoker-proxy-binding-name>这个名字需要与上边第二步配置的完全匹配。
 
<jboss>
    
  <enterprise-beans>
 
    <message-driven>         
      <ejb-name>RecieveMdBean</ejb-name>
      <configuration-name>Standard Message Driven Bean</configuration-name>
      <destination-jndi-name>queue/lotappQueue</destination-jndi-name>
         <invoker-bindings>
            <invoker>                     <invoker-proxy-binding-name>lottery-mdb-invoker</invoker-proxy-binding-name>
            </invoker>
         </invoker-bindings>
        </message-driven>
   
    </enterprise-beans>
</jboss>
 
 
Ok,我们完整的jboss.xml文件内容如下:
 
<jboss>
 
   <invoker-proxy-bindings>
      <invoker-proxy-binding>
         <name>lottery-mdb-invoker</name>
         <invoker-mbean>does-not-matter</invoker-mbean>
         <proxy-factory>org.jboss.ejb.plugins.jms.JMSContainerInvoker</proxy-factory>
         <proxy-factory-config>
            <JMSProviderAdapterJNDI>QueuehostJMSProvider</JMSProviderAdapterJNDI>
            <ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>
            <MinimumSize>1</MinimumSize>
            <KeepAliveMillis>30000</KeepAliveMillis>
            <MaximumSize>15</MaximumSize>
            <MaxMessages>1</MaxMessages>
            <MDBConfig>
               <ReconnectIntervalSec>10</ReconnectIntervalSec>
               <DLQConfig>
                  <DestinationQueue>queue/DLQ</DestinationQueue>
                  <MaxTimesRedelivered>10</MaxTimesRedelivered>
                  <TimeToLive>0</TimeToLive>
               </DLQConfig>
            </MDBConfig>
         </proxy-factory-config>
      </invoker-proxy-binding>
   </invoker-proxy-bindings>   
 
  <enterprise-beans>
 
    <message-driven>         
      <ejb-name>RecieveMdBean</ejb-name>
      <configuration-name>Standard Message Driven Bean</configuration-name>
      <destination-jndi-name>queue/lotappQueue</destination-jndi-name>
         <invoker-bindings>
            <invoker>     
               <invoker-proxy-binding-name>lottery-mdb-invoker</invoker-proxy-binding-name>
            </invoker>
         </invoker-bindings>
        </message-driven>
   
    </enterprise-beans>
</jboss>

Jboss控制台(WebConsole/J2EE Domains/JBoss management/j2ee resource/local jms/)下可以看到消息总数。

Continue reading jboss jms配置

jms笔记

 

Publish-and-subscribe模式:topic
一对多,推送消息
Point-to-point模式:queue
只保证一个接收者收到,要求客户端自己查询获取。
依据jms规范,消息总是要保证送达的,中间的如有短线等故障,再次连接后任然可以获得。

在容器中,不要使用SessionBean或EntityBean作为消息接收者,这关系到线程阻塞问题,标准的方法是使用MessageDriveBean来接收消息。

MDB是无状态的,事务的。
selector是依据消息属性来选择的,使用sql-92 where 后面的语法.
Acknowledge mode是用以判断消息已发送的模式,Auto-acknowledge 和 Dups-ok-acknowledge。
Auto-acknowledge是消息一旦发送给MDB就通知
Dups-ok-acknowledge则说明通知时间无所谓并允许重复发送(当JMS认为消息发送失败时)。这种主要是为网络性能考虑,实际上作用不大。
并且这个设置只当bean-managed transactions, or with the container-managed transaction attribute NotSupported 时才起作用,一般都是容器管理的,会忽略这个配置。

【wsad设置JMS】
需要在设置ConnectionFactory和Queue/Topic
对于Queue要在如下图这里添加。

jms-wsad

注意createQueueSession(false, 0);虽然一般建议使用true, 但是这里是简单的测试,上下文没有事务,所以如果用true会导致rollback,故此处设为false.
topic一直没试通,配置还是在控制台里面配置才配成功的,但是代码里面又抛异常……

Continue reading jms笔记

【转】java Date总结

 

1.计算某一月份的最大天数

Calendar time=Calendar.getInstance();
time.clear();
time.set(Calendar.YEAR,year); //year 为 int
time.set(Calendar.MONTH,i-1);//注意,Calendar对象默认一月为0          
int day=time.getActualMaximum(Calendar.DAY_OF_MONTH);//本月份的天数
注:在使用set方法之前,必须先clear一下,否则很多信息会继承自系统当前时间

2.Calendar和Date的转化

(1) Calendar转化为Date
Calendar cal=Calendar.getInstance();
Date date=cal.getTime();

(2) Date转化为Calendar
Date date=new Date();
Calendar cal=Calendar.getInstance();
cal.setTime(date);

3.格式化输出日期时间 (这个用的比较多)

Date date=new Date();
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String time=df.format(date);
System.out.println(time);

4.计算一年中的第几星期

(1)计算某一天是一年中的第几星期
Calendar cal=Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.DAY_OF_MONTH, 3);
int weekno=cal.get(Calendar.WEEK_OF_YEAR);

(2)计算一年中的第几星期是几号
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
Calendar cal=Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.WEEK_OF_YEAR, 1);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(df.format(cal.getTime()));
输出:
2006-01-02

5.add()和roll()的用法(不太常用)

(1)add()方法
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
Calendar cal=Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.DAY_OF_MONTH, 3);
cal.add(Calendar.DATE, -4);
Date date=cal.getTime();
System.out.println(df.format(date));
cal.add(Calendar.DATE, 4);
date=cal.getTime();
System.out.println(df.format(date));
输出:
    2006-08-30
    2006-09-03
(2)roll方法
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.DAY_OF_MONTH, 3);
cal.roll(Calendar.DATE, -4);
date=cal.getTime();
System.out.println(df.format(date));
cal.roll(Calendar.DATE, 4);
date=cal.getTime();
System.out.println(df.format(date));
输出:
    2006-09-29
    2006-09-03
可见,roll()方法在本月内循环,一般使用add()方法;

6.计算两个任意时间中间的间隔天数(这个比较常用)
(1)传进Calendar对象
    public int getIntervalDays(Calendar startday,Calendar endday)...{      
        if(startday.after(endday))...{
            Calendar cal=startday;
            startday=endday;
            endday=cal;
        }   
        long sl=startday.getTimeInMillis();
        long el=endday.getTimeInMillis();
      
        long ei=el-sl;          
        return (int)(ei/(1000*60*60*24));
    }
(2)传进Date对象

    public int getIntervalDays(Date startday,Date endday)...{       
        if(startday.after(endday))...{
            Date cal=startday;
            startday=endday;
            endday=cal;
        }       
        long sl=startday.getTime();
        long el=endday.getTime();      
        long ei=el-sl;          
        return (int)(ei/(1000*60*60*24));
    }
(3)改进精确计算相隔天数的方法
    public int getDaysBetween (Calendar d1, Calendar d2) ...{
        if (d1.after(d2)) ...{
            java.util.Calendar swap = d1;
            d1 = d2;
            d2 = swap;
        }
        int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR);
        int y2 = d2.get(Calendar.YEAR);
        if (d1.get(Calendar.YEAR) != y2) ...{
            d1 = (Calendar) d1.clone();
            do ...{
                days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);//得到当年的实际天数
                d1.add(Calendar.YEAR, 1);
            } while (d1.get(Calendar.YEAR) != y2);
        }
        return days;
    }
注意:通过上面的方法可以衍生出求任何时间,如要查出邮箱三周之内收到的邮件(得到当前系统时间-再得到三周前时间)用收件的时间去匹配 最好装化成 long去比较
如:1年前日期(注意毫秒的转换)
   java.util.Date myDate=new java.util.Date();
   long myTime=(myDate.getTime()/1000)-60*60*24*365;
   myDate.setTime(myTime*1000);
   String mDate=formatter.format(myDate);

7. String 和 Date ,Long 之间相互转换 (最常用)

字符串转化成时间类型(字符串可以是任意类型,只要和SimpleDateFormat中的格式一致即可)
通常我们取时间跨度的时候,会substring出具体时间--long-比较

java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("M/dd/yyyy hh:mm:ss a",java.util.Locale.US);
java.util.Date d = sdf.parse("5/13/2003 10:31:37 AM");
long dvalue=d.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String mDateTime1=formatter.format(d);

8. 通过时间求时间

年月周求日期
SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM F E");
java.util.Date date2= formatter2.parse("2003-05 5 星期五");
SimpleDateFormat formatter3 = new SimpleDateFormat("yyyy-MM-dd");
String mydate2=formatter3.format(date2);

求是星期几
mydate= myFormatter.parse("2001-1-1");
SimpleDateFormat formatter4 = new SimpleDateFormat("E");
String mydate3=formatter4.format(mydate);

9. java 和 具体的数据库结合

在开发web应用中,针对不同的数据库日期类型,我们需要在我们的程序中对日期类型做各种不同的转换。若对应数据库数据是oracle的Date类型,即只需要年月日的,可以选择使用java.sql.Date类型,若对应的是MSsqlserver 数据库的DateTime类型,即需要年月日时分秒的,选择java.sql.Timestamp类型
你可以使用dateFormat定义时间日期的格式,转一个字符串即可

class Datetest{
*method 将字符串类型的日期转换为一个timestamp(时间戳记java.sql.Timestamp)
*@param dateString 需要转换为timestamp的字符串
*@return dataTime timestamp

public final static java.sql.Timestamp string2Time(String dateString)
throws java.text.ParseException {
DateFormat dateFormat;
dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.SSS", Locale.ENGLISH);//设定格式
//dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale.ENGLISH);
dateFormat.setLenient(false);
java.util.Date timeDate = dateFormat.parse(dateString);//util类型
java.sql.Timestamp dateTime = new java.sql.Timestamp(timeDate.getTime());//Timestamp类型,timeDate.getTime()返回一个long型
return dateTime;
}

*method 将字符串类型的日期转换为一个Date(java.sql.Date)
*@param dateString 需要转换为Date的字符串
*@return dataTime Date

public final static java.sql.Date string2Date(String dateString)
throws java.lang.Exception {
DateFormat dateFormat;
dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
dateFormat.setLenient(false);
java.util.Date timeDate = dateFormat.parse(dateString);//util类型
java.sql.Date dateTime = new java.sql.Date(timeDate.getTime());//sql类型
return dateTime;
}

public static void main(String[] args){
Date da = new Date();
注意:这个地方da.getTime()得到的是一个long型的值
System.out.println(da.getTime());

由日期date转换为timestamp

第一种方法:使用new Timestamp(long)
Timestamp t = new Timestamp(new Date().getTime());
System.out.println(t);

第二种方法:使用Timestamp(int year,int month,int date,int hour,int minute,int second,int nano)
Timestamp tt = new Timestamp(Calendar.getInstance().get(
      Calendar.YEAR) - 1900, Calendar.getInstance().get(
      Calendar.MONTH), Calendar.getInstance().get(
      Calendar.DATE), Calendar.getInstance().get(
      Calendar.HOUR), Calendar.getInstance().get(
      Calendar.MINUTE), Calendar.getInstance().get(
      Calendar.SECOND), 0);
System.out.println(tt);

try {
String sToDate = "2005-8-18";//用于转换成java.sql.Date的字符串
      String sToTimestamp = "2005-8-18 14:21:12.123";//用于转换成java.sql.Timestamp的字符串
      Date date1 = string2Date(sToDate);
      Timestamp date2 = string2Time(sToTimestamp);
System.out.println("Date:"+date1.toString());//结果显示
System.out.println("Timestamp:"+date2.toString());//结果显示
}catch(Exception e) {
e.printStackTrace();
}
}

Continue reading 【转】java Date总结

maven-jetty webapp

 

在myeclipse中,需要修改classpath,将输出文件夹指向src/main/webapp,这是maven指定的路径。

天生一对"Maven2+Jetty" -- Maven2创建并管理WebApp,并使用Maven Jetty Plugin在Eclipse中调试

Maven2代比1代改进很多,其中主要强调的是--它不仅仅是个依赖包管理器!
开始先要推荐一个专讲Maven2的电子书给大家,对MAVEN学习相当有助益:Better Builds with Maven  


下面就专门介绍下Maven2对WEBAPP在管理和调试方面的支持。

1.创建项目

mvn archetype:create -DgroupId=com.mycompany.app -DartifactId=my-webapp -DarchetypeArtifactId=maven-archetype-webapp

也可参看这里

创建要注意遵循MAVEN的目录结构,尤其要注意源文件要放在main/java下:

2. POM文件的配置

这里要特别注意对resource一节的配置,因为我的SPRING以及WEB相关的XML是放在WEB-INF目录,为了在unit test的时候也能用,加入了对这些配置文件的引用。相当于加了一个classpath。

这里还有个插曲:不知为何MAVEN2里没有JTA的包,自动下载时会有提示教你如何手工通过命令加入,非常简单。

JETTY的plugin是为后面用它来调试做准备。

DWR也是目前WEB开发一个热选。

另外,为使用JAVA5代来编译,加入了maven-compiler-plugin一节。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation
="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 
<modelVersion>4.0.0</modelVersion>
 
<groupId>com.exchangebit.nms</groupId>
 
<artifactId>ebnms</artifactId>
 
<packaging>war</packaging>
 
<version>1.0-SNAPSHOT</version>
 
<name>ebnms Maven Webapp</name>
 
<url>http://maven.apache.org</url>
      
 
<build>
   
<finalName>ebnms</finalName>
    
     
<resources>
       
<resource>
         
<directory>src/main/java</directory>
         
<includes>
           
<include>**/*.xml</include>
         
</includes>
       
</resource>
       
<resource>
         
<directory>src/main/webapp/WEB-INF</directory>
         
<includes>
           
<include>**/*.xml</include>
           
<include>**/log4j.properties</include>
         
</includes>
       
</resource>
     
</resources>
      
     
<plugins>
       
<plugin>
         
<groupId>org.apache.maven.plugins</groupId>
         
<artifactId>maven-compiler-plugin</artifactId>
         
<configuration>
           
<source>1.5</source>
           
<target>1.5</target>
         
</configuration>
       
</plugin>
        
     
<plugin>
       
<groupId>org.mortbay.jetty</groupId>
       
<artifactId>maven-jetty-plugin</artifactId>
     
</plugin>        
  
     
</plugins>
   
</build>    
      
 
<dependencies>
   
<dependency>
     
<groupId>junit</groupId>
     
<artifactId>junit</artifactId>
     
<version>3.8.1</version>
     
<scope>test</scope>
   
</dependency>
        
   
<dependency>
     
<groupId>org.hibernate</groupId>
     
<artifactId>hibernate</artifactId>
     
<version>3.1</version>
   
</dependency>
    
   
<dependency>
     
<groupId>log4j</groupId>
     
<artifactId>log4j</artifactId>
     
<version>1.2.11</version>
   
</dependency>
   
<dependency>
     
<groupId>mysql</groupId>
     
<artifactId>mysql-connector-java</artifactId>
     
<version>3.1.11</version>
     
<scope>runtime</scope>
   
</dependency>
   
<dependency>
     
<groupId>javax.servlet</groupId>
     
<artifactId>servlet-api</artifactId>
     
<version>2.4</version>
     
<scope>provided</scope>
   
</dependency>
   
<dependency>
     
<groupId>javax.servlet</groupId>
     
<artifactId>jstl</artifactId>
     
<version>1.1.2</version>
     
<scope>runtime</scope>
   
</dependency>
   
<dependency>
     
<groupId>taglibs</groupId>
     
<artifactId>standard</artifactId>
     
<version>1.1.2</version>
     
<scope>runtime</scope>
   
</dependency>
   
<dependency>
     
<groupId>org.springframework</groupId>
     
<artifactId>spring</artifactId>
     
<version>1.2.6</version>
   
</dependency>
        
   
<dependency>
     
<groupId>dwr</groupId>
     
<artifactId>dwr</artifactId>
     
<version>1.1.3</version>
   
</dependency>        
 
</dependencies>
  
</project>

代码放入/main/java后,可以在项目目录下执行:
mvn compile来做编译尝试,
也可以用mvn war直接生成打包文件,
当然最后可以用 mvn jetty:run来运行你的WEBAPP!

3.  在Eclipse中配置jetty进行调试
要把之前的项目导入Eclipse首先让maven为我们生成Eclipse工程文件,执行:
mvn eclipse:eclipse
再把M2_REPO加入到Eclipse的classpath中,有两种方法,其中的b)方法是有效的:
a) mvn -Declipse.workspace=<path-to-eclipse-workspace> eclipse:add-maven-repo
b) Window > Preferences. Select the Java > Build Path > Classpath Variables page

之后,就可以通过Eclipse的File->Import功能将工程导入。

有人为了使用WEBAPP开发功能,而装象MYECLIPSE这样的巨物。有了JETTY,通过轻松配置就可以实现比TOMCAT更快更便捷的容器,所以在调试时强力推荐这个东东。下面就来看下如何配置。

先下配置一个外部工具,来运行JETTY:
选择菜单Run->External Tools->External Tools ...在左边选择Program,再点New:
配置Location为mvn完整命令行。

选择Working Directory为本项目。

Arguments填写:jetty:run

再点选Enviroment页:加入MAVEN_OPTS变量,值为:
-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=4000,server=y,suspend=y
其中,如果suspend=n 表示不调试,直接运行。

然后,点APPLY,再关闭本对话框。
另外注意一点,好像external tool菜单项在java browering的perspective下才会出现。如果在java下看不见,可以切换下试试。

下面新建运行配置:
点选run->debug...
选中左树中的Remote Java Application,再点New。
选择你的项目,关键是要填和之前设置外部工具时相同的端口号。

配置就完成了,正面开始调试运行:
首先要把JETTY运行起来(有点象TOMCAT里的运行APPSERVER),从Run->External Tools中选择之前配置的外部工具运行,这时LOG里会显示:
listening at port 4000字样,
再选择Run->Debug选择我们刚建的运行配置,这时程序就RUN起来了,可以通过WEB进行访问,设置断点调试了。

后记:
在ECLIPSE中,有更方便高效的调试方式,点这里

Continue reading maven-jetty webapp

MD5 JAVA

private static String dumpBytes(byte[] bytes)
    {
        int i;
        StringBuffer sb = new StringBuffer();
        for (i = 0; i < bytes.length; i++)
        {
            if (i % 32 == 0 && i != 0)
            {
                sb.append("\n");
            }
            String s = Integer.toHexString(bytes[i]);
            if (s.length() < 2)
            {
                s = "0" + s;
            }
            if (s.length() > 2)
            {
                s = s.substring(s.length() - 2);
            }
            sb.append(s);
        }
        return sb.toString();
    }
    public static String MD5Encode(String origin)
    {
        String resultString = null;
        try
        {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            resultString = dumpBytes(md.digest(resultString.getBytes()));
        }
        catch (Exception ex)
        {
            throw new RuntimeException(ex);
        }
        return resultString;
    } 

Continue reading MD5 JAVA

rose 反向工程【推荐EA,rose根本不行】

 

Rational rose生成代码及其反向工程

关键词Rational    rose    生成代码    其反向工程                                          

Rational rose生成代码及其反向工程
一 通过模型生成代码
rose帮助位于 HELP>>CONTENTS>>ROSE JAVA>>HOW TO >>FORWARD ENGINEER FROM  ROSE  TO JAVA SOURCE
下面是简单翻译和图文以及注意事项
步骤 :  1 Checking for Java Syntax Errors
3 Generating Java Source from a Class Diagram
4 Mapping Components for Code Generation
5 Browsing the Java Source
6 Completing the Generated Java Source
 
当你尝试把模型组件转化成代码框架时候,应该考虑到先检查将要生成的类有无语法错误。
1、打开你要专化的目标diagram
2、选择你要转化的包或者类
3、单击  tools>java/j2ee>  Syntax Check 来检查目标代码是否符合规范,比如命名错误。
4、察看rose log窗口(下方)察看检验结果,如果有错误,即errors那么生成的代码很可能无法通过编译
5、根据需要校正这些组件或者图(Correct the components as needed.)
6、复 步骤3直到检验不出错误,然后你就可以进入下一步了(Generating Java Source from a Component Diagram)假设以上步骤已经搞定了error
7、选择你要转化的包或者类
8、单击 Tools > Java/J2EE > Generate Code一般来说如果你还没有将一个package或者组件映射到一个rose的classpath目录中(就是指定生成的东西放哪里),那么系统不会允许你在接下来的界面里点ok,那么现在就编辑目标路径
9、点classpath entries下的edit按钮,再出现的界面右上角找new(insert)(删除左边那个),然后在列表里新增的行里选择目标路径,你可以选择目标是生成一个zip,jar,还是一个目录,我们选择目录。指定目录,ok,那么你选择的路径就新建成功了,选择这个路径,点ok回到界面(层次 好多阿,界面很丑阿)
10、现在你看到classpath entries里有东西了,选择右侧列表里你要转换的包或者组件,点assign,即分配给目标classpth,理论上你可以把选择好的包组件或者类图分别分配个多个classptah
对象。点ok开始生成
11、成功后就可以到指定的classpath下看代码了,生成的代码之间拥有如类图所示的关系。

二 反向功能
rose 帮助位于 HELP>>CONTENTS>>ROSE JAVA>>HOW TO >>REVERSE ENGINEER FROM  JAVA SOURCE TO ROSE反向工程就是通过java代码生成或者更新一个模型的过程。你可以用ROSE对以下文件进行反向
  A.Java source code (.java files)
  B.Java bytecodes (.class files)
  C.zip, .cab, and .jar files
1、 Open the model you want to create or update.
打开一个你刚创建或者想更新的模型新建一个class diagram(如果你还不会,那么这篇文章就别看了)
2、单击Tools > Java/J2EE > Reverse Engineer
     那么现在大家可以想象一下rose会怎么做,刚才是选择了图,创建目标路径,生成代码,那么现在是否指定路径读文件生成图呢,you can say that again!!
在出现的界面上选择一个classpath(如果已经存在)当然,你也可以通过edit classpath按钮新建一个(新建路径的界面刚才讲过了,不再累赘),然后选择这个classpath,更改下面的filter下拉列表,更改目标文件类型(注意不仅仅三行,可以滚动的,对rose的界面真是垃圾这一点又深有体会了),我们这里选择.java,如果这个classptah下存在.java文件,那么就会被列出来 。
注意:你可以通过 add添加选中的文件,也可以通过add all添加所有列出来的,更可以通过 add recursive 递归添加这个路径下所有的文件和子目录下所有文件等等。可以看到rose并不会自动列出甚至显示有没有子目录,从添加好的文件里选择你想反向的文件,点 Reverse 开始创建或者更新无论成功还是失败都会警告,并有log。有错你就改到没错为止。
假设你成功了,点击done结束反向,回到rose主界面。           
注意:rose并不会针对你反向过来的类和组件自动生成图,生成的class已经按照包关系列在你的class diagram下面,你需要把他们加到你的图中去(靠,什么玩艺) ,你有两种方法让这个半自动反向工程化上句号。
   1、手工把class或者组件拖拉到目的图里
   2、在目标图的界面下点击 Query > Add Classes 或者 Query > Add Components ,选择视图方式,一般是logic view,选择要拖拉的类或者组件,>>或者all,点ok完成。生成的类图即反映了代码本身之间的关系。

Continue reading rose 反向工程【推荐EA,rose根本不行】

mule-jxpath-filter 示例

/>myjmx-plugin<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesource.org/schema/mule/core/2.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:spring="http://www.springframework.org/schema/beans"
xmlns:stdio="http://www.mulesource.org/schema/mule/stdio/2.2"
xmlns:vm="http://www.mulesource.org/schema/mule/vm/2.2"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.mulesource.org/schema/mule/core/2.2 http://www.mulesource.org/schema/mule/core/2.2/mule.xsd
http://www.mulesource.org/schema/mule/stdio/2.2 http://www.mulesource.org/schema/mule/stdio/2.2/mule-stdio.xsd
http://www.mulesource.org/schema/mule/vm/2.2 http://www.mulesource.org/schema/mule/vm/2.2/mule-vm.xsd
http://www.mulesource.org/schema/mule/xml/2.2 http://www.mulesource.org/schema/mule/xml/2.2/mule-xml.xsd
"
>

<description>

</description>

<model name="adapterModel">
<service name="AdapterService">
<inbound>
<vm:inbound-endpoint path="xxx/adapter"
synchronous="true" />
</inbound>
<outbound>
<filtering-router>
<vm:outbound-endpoint path="xxx/adapter/ccc"
synchronous="true" />
<expression-filter evaluator="jxpath"
expression="(adapter/header/trx/@value)='logadd'" />
</filtering-router>
<filtering-router>
.....如此重复
</filtering-router>
</outbound>
</service>
<service name="sdoService">
<inbound>
<vm:inbound-endpoint path="xxx/adapter/ccc"
synchronous="true" />
</inbound>
<component class="cc.xxx.adapter.TestComponent"></component>
</service>
</model>

</mule>

Continue reading mule-jxpath-filter 示例

【转】wxPython评估笔记

wxPython评估笔记

|  | 评论(4)

最近写的一点笔记,留作备忘。

================================================================

wxPython(1)wxWidgets

新开张的一个项目需要同时支持Windows和Linux的图形界面,以及内里对复杂XML的处理。又需要去寻找solution了。XML的处理简单,交给Perl去做,Perl的hash结构和simple xml模块足够快速打败这个任务。而且Perl程序也可以很方便地打包(linux上用pp,Windows上用ActivePerl)成可移植二进制包。而GUI的跨平台设计,简单的考虑,有三个可能方向:

QT - 在Linux可用QT Designer,WYSIWYG的设计界面很方便。Windows上不详。但是QT的license对商业应用有限制 
Java - 人人都知道它跨平台,我们之前开发GUI也都一向用控件集合SWT+文档视图类JFace,不过这玩意的开发效率和运行效率都真的不咋地 
wxWidgets - 最近几年比较热门的一个C++图形库,本质上用本地控件,在不同平台上效果会和本地主题一致,图形库在Linux上是基于GTK的,Windows上基于Windows Platform SDK。形式上它和MFC框架很像,用过MFC的人多半都能很快进入状况。

我以前MFC玩得多了,Qt和Java也都有所了解也都不太满意,那么首先拿wxWidgets体验下,需要关注的是安装、快速开发、打包

Windows安装

首先需要一个本地C++编译器。当然可以装MinGW之类的编译器,我懒得搞了,装了个Visual Studio.NET 2003,比较老的版本了。其实微软网站上现在Visual Studio.NET C++ 2008 express是免费下载的,但我不确定那个免费的包里头有没有Wind32 Platform SDK,也许需要另外装SDK。总之装好之后把nmake所在目录加到Windows系路径,把Platform SDK目录加到系统库路径后面就方便了。

然后下载wxWidgets安装。下载的其实是源代码2.8.9版本,需要编译成本地*.o文件,这个还满费时间的。具体编译过程看readme就好,需要注意的是要选择语言格式和后台图形库支持,我选的是UNICODE和gtk2。建议选这两个,因为是主流。

现在就可以用了。找几个例子程序(源代码包里面有的)来编译下,如果有问题,多半都是因为库的路径等原因,稍微调整一下就好。

Linux安装

这个就方便了,现成用g++编译。同样要注意选UNICODE编译选项。

快速开发

很多geek是看不上快速开发工具滴。。。我也同意快速开发工具(RAD tool)并不是那么重要,因为很多稍微复杂一点的界面操作都是快速开发工具做不了的,还是得写代码。但是当你对一个库里头有些什么控件都没概念的时候,一个好的快速开发环境能让你省很多翻书翻手册的时间。很不幸,我试验过了wxDev-C++和wxGlade,前者在我机器上极端不稳定,后者只支持 sizer方式定位控件。

Java 比较熟悉的同志可以把wxWidgets的sizer类类比成Java的container类,对于只玩过MFC的同志们可能有点陌生。简单说,以前 Visual Studio里头,把一个控件拉到dialog后,生成的代码或者资源文件里控件的位置和大小是用(x,y)绝对值来表示的;这个思维很直接,不需要解释。wxWidgets觉得这样不好,当整个窗口被拉大的时候,控件就全挤左上角了,不好看,所以发明了sizer类动态管理控件的位置。 wxWidgets中有很多sizer类,sizer类可以套sizer类或者控件。很像那个装在盒子里的人。。。不过,写HTML写得多的人(这个,很多人折腾过自己blog的模板吧)应该能理解,HTML里面定位不就是用表格和frame嵌套的方式套来套去达到在不同的分辨率下都可以看么,就是太麻烦了。--当然wxWidgets还是支持绝对定位方法的,找不到快速

打包

我没找到合适的打包工具,虽然说编译的是本地可执行代码,可是我得手工把一些wxWidgets的库拉出来才能脱离开发环境运行。麻烦。。。

考虑到用C++开发还需要处理异常,忒麻烦,退缩了,想其它办法去

 

资料

网上很容易找到《Cross-Platform GUI Programming with wxWidgets》和它的中文版本《使用wxWidgets进行跨平台程序开发.pdf》,看起来用它的人还真不少。这本书再加wxWidgets自带的帮助和例子程序,基本上就够用了。

 

================================================================

wxPython(2)Python

前文说到,直接用wxWidgets还是很麻烦的,调查了一下,基于wxWidgets,有很多wrapper,例如wxPerl, wxPython, wxRuby,分别是用Perl/Python/Ruby来包装C++的wxWidgets。先去调查了一下wxPerl,开发度很差,人气很比较差,现在基本是停滞状态。wxRuby是新事物,人气满旺但开发度不够。wxPython大家都认为已经做得不错了。到SourceForge上搜了一圈,发现 Linux上的某BT软件,还有我以前用过的本地blog编辑工具zoundry,都是用wxPython做的,这两个用户量都不小。另外,Zoundry现在开源了,用CVS软件(在windows上可以用TortoiseCVS,Linux自带svn)下载了源代码运行起来,界面很酷。

那么先花几个小时学一下Python。这个脚本语言的语法和支持对象的VB有点像,习惯了C++/Java/Perl这种“类C”语言的人难免刚开始有点皱眉头,但是其实习惯了它的逻辑就好:例如说用空白正确缩进在Python里很重要,重要到了关系程序能不能正确和正常运行的程度;例如说它的函数没有明显的结尾,没有花括号结尾也没有return也可以;变量名没法像perl的use strict一样强制预先定义。

因为要处理XML,考察了一下Python的XML处理。像我这样被perl庞大而且强大的开发者代码共享社区的CPAN宠坏了的人发现Python没有一个好用的开发者社区的时候还是满震惊的。花了不少时间在搜索引擎上才明白ActiveCode上Python的代码比较多,但是也是在找了几个版本之后才找到一个好用的,和Perl的XML::Simple用法相当的XML2Obj模块。

用 XML2Obj读的XML文件到内存以后,是一个嵌套的dictionary,这种结构相当于Perl的hash, 但是,真难用啊,居然没有Data::Dumper模块可以把这个dictionary给打印出来,还得在XML2Obj里面写一个 xmlTree2String( )函数。

有一本叫《A byte of Python》的书,里面有一节叫“Why not Perl?” ,是打击Perl的,理由是用perl开发大型程序很困难--这个人明显没有好好用Perl的面向对象特性的,我们做的Perl程序都相当复杂了,照样组织得好好的。但就是他,也不得不承认Perl的CPAN社区太强大了,希望能够把Perl的模块转到Python上。我很奇怪为啥没有人来组织一个类似的社区网站。

最后,基本上我觉得学计算机语言没啥好说的,看看语法,安装开发环境跑几个例子就好。Python的电子书很容易找到,在这个网站www.pythonid.com里面直接能下载到很多,我就是花了几个小时随便看了两三本,发现网上有人比我还激进,号称十分钟可以学会Python,:-)

参考链接

华蟒用户新闻组 http://groups.google.com/group/python-cn

Python news group http://groups.google.com/group/python

以上两个新闻组的地址是用来搜索的,要发言还得设置outlook express用NNTP协议连新闻服务器。

 

================================================================

wxPython(3)wxPython

对Python语法和面向对象方式稍有了解就可以来玩wxPython了。下载wxPython安装。我在Windows上下载的是runtime binaries, 在Windows XP上安装运行没有任何问题。但是在Linux上只有源代码可以选择,编译的时候出问题了(我的wxWidgets版本是2.8.9),某个类缺少一个 CreateBitmap()方法。看了一下,似乎只是一个wrap而已,自己加一个空的CreateBitmap()就好?搜索一下,果然有人给出了patch,和我想的一样。

Python下使用wxWidgets编程,不二的教程就是《wxPython in Action》,虽然这本书已经有了中文版,但是500多页16开读起来也不是那么容易的,我的办法是直接运行和阅读源代码,可以急速读完:D

使用wxPython的开源项目很多,用wxPython做关键词在google code或者sourceforge上一搜一大把项目,其实我前面推荐的zoundry是很复杂的项目,推荐一个litebook,比较简单易学。另外,豆瓣网是全用python开发的,而网上能搜到的一些豆瓣插件也往往是用python写的,例如“豆瓣好友跟踪”,也有源代码可以参考。

下面说说wxPython的快速开发工具了。wxPython的界面有两种写法,一种是用自带的XRCeditor,创建一个叫XRC的XML文件,界面和控件都写成XML格式固化。因为我的软件的界面会有动态元素,所以跳过这种先进方式,直接寻找用源代码创建控件的方法。

搜来搜去,发现大家都在提一个叫BOA的工具。当下Windows版,安装,然后,呃,开始菜单里什么都没有增加呀?想了下,BOA自己称自己也是基于wxPython的,那么全硬盘搜索下"boa.py”,果然在python的site packages里面找到了,直接python boa.py,一个类似于以前Delphi开发环境的GUI就出来了。

前面说过wxWidgets的布局是用一个叫sizer的类,我不用搞那么复杂,直接按绝对像素布置控件就好。那么就简单了,在BOA里创建一个 frame, frame上创建几个panel, 把控件放在不同的panel里想要的位置,然后点那个对勾图标,代码就生成好了。直接运行,想要的窗口就出来了。BOA还支持消息映射,可以在GUI里添加消息映射和消息处理函数。

结论:Python+wxWidgets+BOA 非常好用!

 

================================================================

wxPython(4)distribution

基于wxPython的软件做好,一定要打包的,你没法保证目标机器上的运行环境和本机一致。

打包Python程序有很多种选择,在Windows上很简单,用py2exe。只要写一个setup.py, 然后使用python的标准分发接口disutilis的标准用法

python setup.py py2exe

如果setup写得不对会生成很多文件,希望出来的结果干净一点,setup.py要这样写,设置bundle_files

from distutils.core import setup  
import py2exe  
includes = ["encodings", "encodings.*"]  
options = {"py2exe":  
            {   "compressed": 1,  
                "optimize": 2,  
                "includes": includes,  
                "bundle_files": 1  
            }  
          }  
setup(     
    version = "0.1.0",  
    description = "radargraph",  
    name = "radargraph",  
    options = options,  
    zipfile=None,  
    windows=[{"script": "myApp.py", "icon_resources": [(1, "myApp.ico")] }],    
    )

其中myApp.py和myApp.ico要改成自己的文件。做出来的有一个win32可执行程序,一个vc7的dll,两个文件而已,很干净。大小大约在4M到10M之间。

在Mac上据说py2App的表现和py2exe一样方便,我没有Mac系统没法试验。

在Linux上有点麻烦,我试验了Python自带的freeze.pl,以及cx_FreezepyInstaller。这三种工具都有标准python disutils接口,使用方法都一样,写一个setup.pl文件(当然不同的工具对这个的格式要求可能不一样,详细见各个工具的手册和例子),然后运行python setup.pl xxx (这里xxx是各工具的名字)。

试验结果如下,pyInstaller, 打包失败,原因不详,也许是我setup.pl写得不好?但我看了又看,没看出问题,然后发现它网站上的例子我也编译不成功,没耐心了。 freeze.pl打包成功,但是拷到其它Linux机器上运行失败,因为库文件没有拷全。我估计自己手工把python和wxWidgets的*.so 文件拷过来应该可以,但是查找dependency很麻烦啊。cx_Freeze是最后一棵稻草。运行下来,嘿嘿,所有*.so都拷全了,虽然有些不必要的gcc的*.so它也拷过来了。最后做出来的是一个可执行文件和十多个so文件,其中libwx_gtk2ud_core-2.8.so.0文件就有 20M。这个tar.gz之后还有20多M。。。确实能够工作,可是尺寸太大了!我们想要的是一个能够通过email发给客户的版本,这个太巨。

-----------另外,关于wxPython用到的资源文件----------

用 BOA来在界面上创建Bitmap图标或者bitmap时,生成的代码是直接调用bitmap文件。这样子生成的可执行文件,在目标机器上可能会找不到资源。解决方法是参考《wxPython in Action》的第二章的例子代码,里面有个images.py,是由Python的XRCeditor里面的encode_bitmaps.py生成的资源文件。打开encode_bitmaps.py看一下就明白应该怎么做,会生成一个python文件,里面有若干PyEmbeddedImage对象(和第二章的例子有点不一样了)。例如

Image_title = PyEmbeddedImage( 
    "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAAA3NCSVQICAjb4U/gAAAek0lE" 
)

要用的时候就在需要BITMAP的地方Image_title.GetBitmap()就好了。缺点是这样改之后,BOA就不能load这个项目了,因为BOA不认PyEmbeddedImage。

----------------------------------------------------------

继续寻找新方法。大家都知道,连接Python和C/C++库的桥梁有: 
1. 直接使用Python提供的C API - 这个很麻烦 
2. SWIG 其实SWIG不只支持Python, 它功能很强大,很多脚本语言都用它和C接口。当年wxPython开发时1.0版本用方法1,后来没法维护了,最后只好改成SWIG。缺点是很繁琐。 
3. Boost.Python 据说用这个接口C++很方便 
4. Pyrex 

pyrex,是一种新的脚本语言。它用类似于Python的语言来写代码,然后用pyrex工具变成C代码,最后编译成可执行程序。同时pyrex代码中可以使用和调用Python代码。于是有些人就利用这个方式来通过pyrex把python变成C,再编译成可执行代码。David McNab有一个关于如何做的教程,我试验过了,简单的Python程序可以;但是对于wxPython程序,转出来的C文件编译不成功,看起来对于wxWidgets的支持有问题。

参考

牡蛎的如何编译Python程序 
Pyrex, 和Python的C扩展

------------------------------------------------------------

最后这个项目可耻地还是用了Java SWT+Jface。原因就是20M的可执行包太大了。其实,对于没有这种限制的项目,wxPython+BOA+cx_Freeze真是飞速、稳定、可分发的开发环境,强烈推荐。

Continue reading 【转】wxPython评估笔记

Pagination


Total views.

© 2013 - 2019. All rights reserved.

Powered by Hydejack v6.6.1