笔记

way

2011年10月8日

最近在网上看到的相关材料都比较陈旧,也太简略,参看了一下其他人的内容,针对Hive2.1.1做点分享:
1)下载apache-hive-2.1.1-bin.tar.gz

2)解压缩,下面的命令行如启动报错,请自行查略Hive启动配置

3)启动hiveserver2 (非必须,使用jdbc访问的时候才使用)
bin目录下
hive --service hiveserver2 -p10001来启动hiveserver2 服务(默认为10000端口)
nohup hive --service hiverserver2 -p10001可以在后台跑
4)hive脚本运行流程
bin目录下,使用命令方法为:
./hive <parameters> --service serviceName <service parameters>
举例:hive --debug :
   查看bin/hive文件
流程中会判断$1=‘--debug’则$DEBUG=‘--debug’
 
if [ "$DEBUG" ]; then
  if [ "$HELP" ]; then //如还有--help,就会执行debug_help方法。
    debug_help
    exit 0
  else
    get_debug_params "$DEBUG"
    export HADOOP_CLIENT_OPTS="$HADOOP_CLIENT_OPTS $HIVE_MAIN_CLIENT_DEBUG_OPTS"//设置HIVE_MAIN_CLIENT_DEBUG_OPTS的参数中加入debug相应参数
  fi
fi
if [ "$SERVICE" = "" ] ; then
  if [ "$HELP" = "_help" ] ; then
    SERVICE="help"
  else
    SERVICE="cli"     //默认赋值cli
  fi
fi
这个shell脚本很多变量应该是在其他sh文件中定义,其中$SERVICE_LIST就是其他很多sh文件的最开始形成的:export SERVICE_LIST="${SERVICE_LIST}${THISSERVICE} "
hive脚本最后的$TORUN "$@" ,默认情况下TORUN其实就是cli,即执行/ext/cli.sh脚本,该脚本中主要是调用/ext/util/execHiveCmd.sh 来执行最后的CliDriver。
 【shell脚本中的$*,$@和$#
举例说:
脚本名称叫test.sh 入参三个: 1 2 3
运行test.sh 1 2 3后
$*为"1 2 3"(一起被引号包住)
$@为"1" "2" "3"(分别被包住)
$#为3(参数数量)
即exec $HADOOP jar ${HIVE_LIB}/$JAR $CLASS $HIVE_OPTS "$@" //1
其中:
$HADOOP=$HADOOP_HOME/bin/hadoop 【hive脚本中定义HADOOP=$HADOOP_HOME/bin/hadoop】
$CLASS=org.apache.hadoop.hive.cli.CliDriver【传入的第一个参数,在cli.sh中有定义】
hadoop脚本(2.7.3为例)中最终会执行:
# Always respect HADOOP_OPTS and HADOOP_CLIENT_OPTS
    HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
    #make sure security appender is turned off
    HADOOP_OPTS="$HADOOP_OPTS -Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER:-INFO,NullAppender}"
 
    export CLASSPATH=$CLASSPATH
    exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS $CLASS "$@" //2
hive的debug参数就是在启动hive脚本时放到HADOOP_OPTS中的
1和2处结合可得到最终的运行命令,查看一下运行结果:ps -ef|grep CliDriver

  /usr/java/jdk1.8.0_101/bin/java -Xmx256m -Djava.net.preferIPv4Stack=true -Dhadoop.log.dir=.. -Dhadoop.log.file=hadoop.log -Dhadoop.home.dir=.. -Dhadoop.id.str=root -Dhadoop.root.logger=INFO,console -Djava.library.path=.. -Dhadoop.policy.file=hadoop-policy.xml -Djava.net.preferIPv4Stack=true -Xmx512m -Dproc_hivecli -XX:+UseParallelGC -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=-Dlog4j.configurationFile=hive-log4j2.properties -Djava.util.logging.config.file=..
  
-Dhadoop.security.logger=INFO,NullAppender org.apache.hadoop.util.RunJar /yuxh/app/apache-hive-2.*/lib/hive-cli-2.*.jar org.apache.hadoop.hive.cli.CliDriver
posted @ 2017-03-29 16:01 yuxh 阅读(1533) | 评论 (0)编辑 收藏
     摘要:   阅读全文
posted @ 2015-09-23 21:14 yuxh 阅读(4369) | 评论 (0)编辑 收藏
appfuse3.5使用Hibernate4.3.6, 而Hibernate日志框架使用了jboss-logging,想在后台打出sql的参数一直无法生效。
检查配置文件,框架里面的两个配置文件,src/test/resources/log4j2.xml(单元测试时配置),src/main/resources/log4j2.xml(运行时配置)
搞清log4j2的配置后,各种修改(主要是
  <Logger name="org.hibernate.SQL" level="trace"/>
  <Logger name="org.hibernate.type" level="trace"/>)
用junit测试任然无法打印出真实参数。根据这些实践,确定log4j2是使用无误生效的,只是org.hibernate这部分的logger一直未起效
参考国内外网站,一直无人回答hibernate4的这个问题,有人指出这部分Hibernate官方文档只是提了一句,一直未更新相关内容。最后有人提到应该是 jboss-logging 的LoggerProviders这个类的问题,看实现对log4j2已经做支持。最后发现 jboss-logging使用的是3.2.0.beta,对比相关类的源代码,更改为3.2.0.Final,生效!

P.S 把这个问题提交给Appfuse官网,issue APF-1478,作者标志为4.0版本修复。
posted @ 2015-07-22 14:11 yuxh 阅读(278) | 评论 (0)编辑 收藏
新电脑装上eclipse4.4.2,导入maven项目之后,依赖库总是有很多错误。最后搜索到可能是eclipse的bug(据说是JAVA_HOME没有正确传递),查看到eclipse默认的是安装的jre目录,修改到jdk目录下,依赖问题解决。
不过目前版本仍然没有解决pom文件的“Plugin execution not covered by lifecycle configuration”错误,暂时忽略不管吧。
posted @ 2015-06-02 10:27 yuxh 阅读(310) | 评论 (0)编辑 收藏
本打算继承一个API中的Parent类(Parent继承自GrandParent类),重写其中的service方法,copy了Parent的service方法。不过发现Parent的service中也有super.service方法。当时考虑直接调用GrandParent的service方法。。。未遂(包括反射也不行)。正好看到老外写的一篇文章,翻译:
在Son类里面写一个test方法:
public void test() {
 
super.test();
 
this.test();
}
反编译之后:
public void test()
    {
    
//    0    0:aload_0         
    
//    1    1:invokespecial   #2   <Method void Parent.test()>
    
//    2    4:aload_0         
    
//    3    5:invokevirtual   #3   <Method void test()>
    
//    4    8:return          
    }
使用ASM可以完成对GrandParent方法的调用
public class GrandParent {
    
public void test() {
            System.out.println(
"test of GrandParent");
    }
}

public class Parent extends GrandParent{
    
public void test() {
        System.out.println(
"test of Parent");
    }
}

public class Son extends Parent{
    
public void test() {
        System.out.println(
"test of Son");
    }
}
调用Son实例的test方法只会执行Son的test方法。而ASM可以修改class,先写一个Example类继承Son,重写test方法

 1 import java.io.FileOutputStream;
 2  
 3 import org.objectweb.asm.ClassWriter;
 4 import org.objectweb.asm.MethodVisitor;
 5 import org.objectweb.asm.Opcodes;
 6  
 7 public class ASMByteCodeManipulation extends ClassLoader implements Opcodes {
 8  
 9  public static void main(String args[]) throws Exception {
10   ClassWriter cw = new ClassWriter(0);
11   cw.visit(V1_1, ACC_PUBLIC, "Example"null"Son"null);
12  
13   // creates a MethodWriter for the (implicit) constructor
14   MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>""()V"null,null);
15   mw.visitVarInsn(ALOAD, 0);
16   mw.visitMethodInsn(INVOKESPECIAL, "Son""<init>""()V");
17   mw.visitInsn(RETURN);
18   mw.visitMaxs(11);
19   mw.visitEnd();
20  
21   // creates a MethodWriter for the 'test' method
22   mw = cw.visitMethod(ACC_PUBLIC, "test""()V"nullnull);
23   mw.visitFieldInsn(GETSTATIC, "java/lang/System""out","Ljava/io/PrintStream;");
24   mw.visitLdcInsn("test of AI3");
25   mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream""println",
26     "(Ljava/lang/String;)V");
27   //Call test() of GrandParent
28   mw.visitVarInsn(ALOAD, 0);
29   mw.visitMethodInsn(INVOKESPECIAL, "GrandParent""test""()V");
30   //Call test() of GrandParent
31   mw.visitVarInsn(ALOAD, 0);
32   mw.visitMethodInsn(INVOKESPECIAL, "Parent""test""()V");
33   //Call test() of GrandParent
34   mw.visitVarInsn(ALOAD, 0);
35   mw.visitMethodInsn(INVOKESPECIAL, "Son""test""()V");
36   mw.visitInsn(RETURN);
37   mw.visitMaxs(21);
38   mw.visitEnd();
39  
40   byte[] code = cw.toByteArray();
41   FileOutputStream fos = new FileOutputStream("Example.class");
42   fos.write(code);
43   fos.close();
44  
45   ASMByteCodeManipulation loader = new ASMByteCodeManipulation();
46   Class<?> exampleClass = loader.defineClass("Example", code, 0,
47     code.length);
48   Object obj = exampleClass.newInstance();
49   exampleClass.getMethod("test"null).invoke(obj, null);
50  
51  }
52 }
输出:
test of AI3
test of GrandParent
test of Parent
test of Son
看看怎样实现的,11行定义一个新的类Example继承Son。22行,Example重写test方法,先打印“test of AI3”,再分别在29、32、35行调用GrandParent、Parent、Son的test方法。
 main方法中,45行创建Example的实例,再用反射调他的test方法。
使用invokespecial这种方式也有局限,只能从子类调用。否则报错:
Exception in thread "main" java.lang.VerifyError: (class: Example, method: test1 signature: (LAI2;)V) Illegal use of nonvirtual function call
posted @ 2012-05-31 11:23 yuxh 阅读(2028) | 评论 (0)编辑 收藏
使用Google calendar v3 API的时候,大量发现Builder使用。比如Credential类,查了查Builder模式的讲解,始终感觉代码的实现和标准定义不太相同。最后发现这种实现方式是《Effective java 2nd》中的一种实现(Item 2: Consider a builder when faced with many constructor parameters)。静态工厂和构造器都有一个通病:对于存在大量可选构造参数的对象,扩展性不好。经典的解决方案是提供多个构造函数,第一个构造函数只有必须的参数,第二个构造函数除了必须参数还有一个可选参数,第三个除了必须参数还有两个可选参数。。。这样下去知道最后一个可选参数出现(telescoping constructor)。这种方案的问题是,当构建对象的时候很容易把其中两个参数的位置放反。。。。(难发现的bug)
另一种解决方案是JavaBean 模式,先调用无参构造函数再调用各个set方法来组装对象。这种方案的问题是不能强制一致性。如果没有set某些必须的参数的话,对象可能处于不一致(
inconsistent)的状态(难发现的bug)。另外一个缺点是JavaBean模式不能让类immutable,需要程序员额外工作保证线程安全。
第三种方式就是Builder设计模式。这种方式混合了telescoping constructor模式的安全性和JavaBean模式的可读性。客户端调用有所有必填参数的构造器(或静态工厂),得到一个builder对象。然后调用builder对象的方法去set各个选填参数。最后调用无参的build方法产生一个immutable的对象实例。immutable对象有非常多优点而且可能很有用。builder的set方法都是返回builder本身,所以调用也是可以chained。如:
  GoogleCredential credentialNew = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
                    .setJsonFactory(JSON_FACTORY).setClientSecrets(clientSecrets)
                    .addRefreshListener(
new CredentialStoreRefreshListener(userID, new DBCredentialStore())).build()
                    .setAccessToken(accessToken).setRefreshToken(refreshToken)
客户端代码很好写,更重要的是易读。Builder模式模拟了在Ada和Python语言里的命名可选参数(named optional parameters)。
同时Builder类设置为static也是对Item 22:Favor static member classes over nonstatic的实践
posted @ 2012-05-30 17:44 yuxh 阅读(369) | 评论 (0)编辑 收藏
以典型的客户端-服务器端授权为例
一 基本流程
使用Google Calendar v3 ,如果以servlet作为代理,可以使用官方示例,自己写一个类A.java继承AbstractAuthorizationCodeServlet类,这个类主要用于跳转到google提供的授权页面,如果用户同意授权,则根据A类中的URL(这个必须和注册的google 回调路径相同,比如oauth_callback否则报错)重定向到B类,B.java 继承AbstractAuthorizationCodeCallbackServlet类,这个访问路径类似http://www.example.com/oauth_callback?code=ABC1234。这里我配置oauth_callback为servlet的访问路径,B类中的
onSuccess方法将根据获得的access Token(这是根据传过来的code获得的)做业务操作。

二 需要参数的情况
有些业务需要用户传参数,直接传参数给A,再试图在B中获取是不行的!B类中只能获取某些固定的参数,如code。要想传用户参数,我们可以在A中先获取,把几个参数组装为json格式字符串(还可以继续base64编码),把这个字符串作为state的值,再重定向到授权页面,同意后state参数可以传到B类,取值解析json字符串(或先base64解码),得到参数。
由于API中AuthorizationCodeRequestUrl有处理state的方法,而AbstractAuthorizationCodeServlet已经直接封装,为了使用setState,直接在A类中继承HttpServlet重写service方法,复制大部分AbstractAuthorizationCodeServlet的内容,稍作修改:
resp.sendRedirect(flow.newAuthorizationUrl().setState(json).setRedirectUri(redirectUri).build());

三 关于refresh token
默认情况下,用户授权之后token会有一个小时的有效期,之后你可以通过refresh token再重新获取token。所以,如果不需要用户再次授权,可以在第一次,保存好token、refresh token、ExpirationTime。实例中用了JDO来实现,自己如果使用数据库保存,可类似写一个类实现CredentialStore类。使用的时候,现在数据库中取出,再创建credential,如:
            GoogleCredential credentialNew = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
                    .setJsonFactory(JSON_FACTORY).setClientSecrets(clientSecrets)
                    .addRefreshListener(new CredentialStoreRefreshListener(userID, new DBCredentialStore())).build()
                    .setAccessToken(accessToken).setRefreshToken(refreshToken)
                    .setExpirationTimeMilliseconds(expirationTimeMilliseconds);
在无效的情况下,Listener会自动去用refresh token请求。
posted @ 2012-05-08 11:40 yuxh 阅读(932) | 评论 (0)编辑 收藏
json格式经常需要用到,google提供了一个处理json的项目:GSON,能很方便的处理转换java对象和JSON表达。他不需要使用annotation,也不需要对象的源代码就能使用。
以字符串为例介绍:
1 。构造json 字符串
  例如要传送json格式的字符串
        String appID = req.getParameter("appID");
        String userID  = req.getParameter("userID");
        Map map = new HashMap();
        map.put("appID", appID);
        map.put("userID", userID);
        Gson gson = new Gson();
        String state = gson.toJson(map);
2.解析json字符串
          JsonParser jsonparer = new JsonParser();//初始化解析json格式的对象
          String state = req.getParameter("state");
          String appID = jsonparer.parse(state).getAsJsonObject().get("appID").getAsString();
          String userID = jsonparer.parse(state).getAsJsonObject().get("userID").getAsString();
posted @ 2012-05-08 10:23 yuxh 阅读(2126) | 评论 (1)编辑 收藏
通用协调时(UTC, Universal Time Coordinated),格林尼治平均时(GMT, Greenwich Mean Time) 由于历史原因,这两个时间是一样的。
北京时区是东八区,领先UTC八个小时,在电子邮件信头的Date域记为+0800。
转换中,最重要的公式就是:
UTC + 时区差 = 本地时间
    public static Calendar convertToGmt(Calendar cal) {
        Date date 
= cal.getTime();
        TimeZone tz 
= cal.getTimeZone();

        System.out.println(
"input calendar has date [" + date + "]");

        
// Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
        long msFromEpochGmt = date.getTime();

        
// gives you the current offset in ms from GMT at the current date
        int offsetFromUTC = tz.getOffset(msFromEpochGmt);
        System.out.println(
"offset is " + offsetFromUTC);

        
// create a new calendar in GMT timezone, set to this date and add the offset     
        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        Calendar utcCal 
= Calendar.getInstance(TimeZone.getTimeZone("UTC"));

        gmtCal.setTime(date);
        //根据东西时区,选择offsetFromUTC为正或负数
        gmtCal.add(Calendar.MILLISECOND, offsetFromUTC);

        utcCal.setTime(date);
        utcCal.add(Calendar.MILLISECOND, offsetFromUTC);

        System.out.println(
"Created GMT cal with date [" + gmtCal.getTime()
                
+ "==" + utcCal.getTime() + "]");
        
return gmtCal;
    }
posted @ 2012-03-15 23:08 yuxh 阅读(1627) | 评论 (0)编辑 收藏
Andriod 到3.2版本为止,webview方式下使用<input type="file" />点击后都没有反应。实际上顶层是有隐含的接口没实现的,可以自己重写这个方法来实现。以phonegap为例:

public class App extends DroidGap {
    
private ValueCallback<Uri> mUploadMessage;
    
private final static int FILECHOOSER_RESULTCODE = 1;

    
/** Called when the activity is first created. */
    @Override
    
public void onCreate(Bundle savedInstanceState) {
        
super.onCreate(savedInstanceState);
        
super.init();
        
// WebView wv = new WebView(this);
        
// wv.setWebViewClient(new WebViewClient());
        this.appView.setWebChromeClient(new CordovaChromeClient(App.this) {
            
// For Android 3.0+
            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
                mUploadMessage 
= uploadMsg;
                Intent i 
= new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType(
"image/*");
                App.
this.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
            }

            
// The undocumented magic method override
            
// Eclipse will swear at you if you try to put @Override here
            public void openFileChooser(ValueCallback<Uri> uploadMsg) {
                mUploadMessage 
= uploadMsg;
                Intent i 
= new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType(
"image/*");
                App.
this.startActivityForResult(Intent.createChooser(i, "File Chooser"), App.FILECHOOSER_RESULTCODE);
            }
        });

        
// setContentView(wv);
        super.loadUrl("file:///android_asset/www/login.html");
    }

    @Override
    
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        
if (requestCode == FILECHOOSER_RESULTCODE) {
            
if (null == mUploadMessage)
                
return;
            Uri result 
= intent == null || resultCode != RESULT_OK ? null : intent.getData();
            mUploadMessage.onReceiveValue(result);
            mUploadMessage 
= null;
        }
    }
}
如果直接的webview方式,extends WebChromeClient即可。 参考:http://stackoverflow.com/questions/5907369/file-upload-in-webview
posted @ 2012-03-12 12:54 yuxh 阅读(5306) | 评论 (1)编辑 收藏
weather.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.net.*"%>
<%
    StringBuffer sbf 
= new StringBuffer();
    
//Access the page
    try {
      
//如果网络设置了代理
        System.setProperty("http.proxyHost""xxx");
        System.setProperty(
"http.proxyPort""80");
        URL url 
= new URL("http://www.google.com/ig/api?weather=london");
        URLConnection urlConn 
= url.openConnection();

        BufferedReader in 
= new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
        String inputLine;
        
while ((inputLine = in.readLine()) != null)
            sbf.append(inputLine);
        in.close();
        System.out.println(
"last="+sbf.toString());
    } 
catch (MalformedURLException e) {
        System.out.println(
"MalformedURLException"+e);
    } 
catch (IOException e) {
        System.out.println(
"IOException"+e);
    }
%><%=sbf.toString()%>
前台js部分:

        var childData   = function(selector, arg)
        {
                
return selector.find(arg).attr('data');
         }
        $.ajax({
            type : 
"GET",
            data : 
"where=" ,
            url : 
"weather.jsp",
            success : 
function(data) {
                console.debug('data
='+data);
                forecast 
= $(data).find('forecast_information');
                cCondition 
= $(data).find('current_conditions');

                city 
= childData(forecast, 'city');
                
if (city != undefined) {
                    date 
= childData(forecast, 'forecast_date');

                    condition 
= childData(cCondition, 'condition');
                    tempC 
= childData(cCondition, 'temp_c');
                    humidity 
= childData(cCondition, 'humidity');
                    icon 
= childData(cCondition, 'icon');
                    $('#city').text(city);
                    $('#date').text(date);
                    $('#condition').text(condition);
                    $('#tempC').html(tempC 
+ '&deg; C');
                    $('#humidity').text(humidity);
                    $('#icon').attr({
                        'src' : 'http:
//www.google.com' + icon
                    });
                    $('#data').stop().show('fast');
                } 
else {
                    $('#error').stop().show('fast');
                }
            }
        });
posted @ 2012-02-22 08:58 yuxh 阅读(216) | 评论 (0)编辑 收藏

1. Code first approach:可能不能完全发挥框架和web services的能量,但能完成目标。减少了学习曲线,不用非常透彻了解web services概念,只要对某个框架有一定了解就能完成任务。
2.Contract first approach:根据服务先写WSDL文件,写好之后使用框架的工具把WSDL转换为依赖框架的代码。

一  介绍

当客户端调用你的web service的时候,他会发送一个消息过来(可能是soap 消息),如:

<foo:concatRequest>
<s1>abc</s1>
<s2>123</s2>
</foo:concatRequest>

这时候如果有一个转换器把这个soap消息转换成java对象,然后调用你提供的java对象(方法)的话将会是非常方便的。几个最流行的库就是充当了这种转换器功能,比如CXF, Axis2 , Metro (jdk6自带的有)。

手动创建WSDL文件比较容易出错,可以使用eclipse进行可视化编辑。

二 生成服务代码

像CXF这样的 web service库可以创建转换器把进来的SOAP 消息转换为Java对象,然后作为参数传给方法。生成这些代码,只需创建一个main:

1 CXF方式:

public static void main(String[] args) { WSDLToJava.main(new String[] { "-server", "-d", "src/main/java", "src/main/resources/SimpleService.wsdl" }); System.out.println("Done!"); }

运行后会生成service endpoint interface(SEI),我们再写一个类(比如SimpleServiceImpl)来实现这个接口,写入自己的业务。还会生成传入消息对应的java对象。同时生成一个服务器类:

public class SimpleService_P1_Server { protected SimpleService_P1_Server() throws Exception { System.out.println("Starting Server"); Object implementor = new SimpleServiceImpl(); String address = "http://localhost:8080/ss/p1"; Endpoint.publish(address, implementor); } public static void main(String args[]) throws Exception { new SimpleService_P1_Server(); System.out.println("Server ready..."); Thread.sleep(5 * 60 * 1000); System.out.println("Server exiting"); System.exit(0); } }

运行这个类你的web service就可以服务了。

2 Axis2 方式

用类似的写main方法,或者配置eclipse的axis2插件可生成:在WSDL文件上,右键->web service->generate java bean skeleton

界面的上半部分针对服务端,可以根据需要调整生成的级别,下半部分是生成客户端。具体的级别可参考eclipse的帮助文档。一路下一步,最后根据命名空间生成包路径的文件,里面有XXSkeletonInterface.java 文件(如果生成的时候选择了生成接口的话),还有一个XXSkeleton实现了这个接口,也是我们需要修改这部分代码完成我们业务的地方。实际上有一个XXMessageReceiverInOut.java的类接收请求的消息,并调用XXSkeletonInterface。使用eclipse的axis2插件的时候,会自动在web-inf文件夹下生成service\xx(你的wsdl服务名),这下面还要一个meta-inf文件夹装有wsd文件和一个services.xml配置文件。services.xml文件可配置包括XXMessageReceiverInOut类在内的选项。

二 生成客户端代码

为了调用这些web service,同样可以用CXF这些库来生成在客户端运行的转换器(称为service stub)。当调用stub里的方法的时候,他会把你的数据/对象 转换为正确的XML格式,然后发送给真正的web service。当他收到响应的时候,又会把XML转回Java。

1 CXF 方式

和生成服务器端类似,使用方法

WSDLToJava.main(new String[] {
"-client",
"-d", "src/main/java",
"src/main/resources/SimpleService.wsdl" });

运行后会生成客户端代码:

public final class SimpleService_P1_Client { private static final QName SERVICE_NAME = new QName("http://ttdev.com/ss", "SimpleService"); private SimpleService_P1_Client() {} public static void main(String args[]) throws Exception { URL wsdlURL = SimpleService_Service.WSDL_LOCATION; if (args.length > 0) { File wsdlFile = new File(args[0]); try { if (wsdlFile.exists()) { wsdlURL = wsdlFile.toURI().toURL(); } else { wsdlURL = new URL(args[0]); } } catch (MalformedURLException e) { e.printStackTrace(); } } SimpleService_Service ss = new SimpleService_Service(wsdlURL, SERVICE_NAME); SimpleService port = ss.getP1(); { System.out.println("Invoking concat..."); com.ttdev.ss.ConcatRequest _concat_parameters = null; java.lang.String _concat__return = port.concat(_concat_parameters); System.out.println("concat.result=" + _concat__return); } System.exit(0); } }

SimpleService_Service是创建的service stub,他模拟了客户端的服务。我们需要修改这个类中的_concat_parameters部分,加入参数:

com.ttdev.ss.ConcatRequest _concat_parameters = new ConcatRequest();
_concat_parameters.setS1("abc");
_concat_parameters.setS2("123");

现在就可以运行客户端代码了。SEI中有一些注解,可以修改,不细说。

 

2 Axis2 方式
和生成服务端类似,利用eclipse插件直接生成,包路径类似,有一个XXStub类,这个类里面有包括请求和应答消息在内的内部类。使用的时候,先对请求消息参数类按业务需求赋值,最后调用Stub的请求方法。可以使用Stub的构造函数指定目标endpoint。

 

posted @ 2011-10-24 00:26 yuxh 阅读(380) | 评论 (0)编辑 收藏

有两种SOAP message风格,documentRPC,他们定义了SOAP message body的格式。使用document风格时(包括wrapped和unwrapped),在wsdl中有一个非空的types部分,这个部分用XML Schema language定义了web service要用到的类型。wsgen工具从SIB(有SEI就足够了)中生成与XSD对应的java类。用java代码生成WSDL文件的时候需要一些java类,wsgen工具可以生成这些Java类,生成的这些java类被称为wsgen artifacts,底层的JWS类库会用到这些类,特别是JAX-B系列的包,会用来转换(marshal)java类实例(that is, Java in-memory objects)为XML类型的XML实例(满足XML Schema document的XML文档实例),

The inverse operation is used to convert (unmarshal) an XML document instance to an in-memory
object, an object of a Java type or a comparable type in some other language。因此wsgen工具生成的artifacts,支持了Java为基础的web service的互操作性。JAX-B类库提供了Java和XSD类型转换的底层支持。

For the most part, the wsgen utility can be used without our bothering to inspect the artifacts that it produces. For the most part, JAX-B remains unseen infrastructure.

wsgen artifacts实际上是wsdl message的数据类型,他们和XML Schema type绑定,每个message的XML Schema types从这些java类型得来的。注:在当前的jdk1.6.24中,已经融入wsgen自动生成的过程,不需手动调用。

wsgen工具可用来生成wsdl文件,如:% wsgen -cp "." -wsdl ch01.ts.TimeServerImpl 。这为TimeServer服务生成了wsdl。用wsgen生成的wsdl和通过访问发布的服务生成的wsdl 有个很大的区别:wsgen生成的没有endpoint,因为这个URL是在发布服务的时候决定的。其他地方两个wsdl是相同的。

wsimport(以前叫wsdl2java和 java2wsdl更形象)工具可使用WSDL生成用来帮助写客户端的artifacts .

1 先契约再编码方式
一个例子:得到一个tempConvert.wsdl文件,使用命令 wsimport -keep -p ch02.tc tempConvert.wsdl ,命令根据wsdl的portType生成一个SEI类,把SEI的interface换为class,再把方法改为实现就可变为SIB。把该SIB发布,再使用命令wsimport -keep -p clientTC http://localhost:5599/tc?wsdl,来生成客户端辅助类
2 编码优先
服务被发布之后,会自动生成WSDL供客户端使用。然而,使用annotations可以控制WSDL或WSDL-generated artifacts的生成。

posted @ 2011-10-08 21:47 yuxh 阅读(552) | 评论 (0)编辑 收藏

导航

<2011年10月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

统计

常用链接

留言簿

随笔分类

随笔档案

收藏夹

博客

搜索

最新评论

阅读排行榜

评论排行榜