2)解壓縮,下面的命令行如啟動報錯,請自行查略Hive啟動配置
-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
用junit測試任然無法打印出真實參數。根據這些實踐,確定log4j2是使用無誤生效的,只是org.hibernate這部分的logger一直未起效
P.S 把這個問題提交給Appfuse官網,issue APF-1478,作者標志為4.0版本修復。
JAVA_HOME沒有正確傳遞
),查看到eclipse默認的是安裝的jre目錄,修改到jdk目錄下,依賴問題解決。不過目前版本仍然沒有解決pom文件的“Plugin execution not covered by lifecycle configuration”錯誤,暫時忽略不管吧。
在Son類里面寫一個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
}
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");
}
}
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(1, 1);
19 mw.visitEnd();
20
21 // creates a MethodWriter for the 'test' method
22 mw = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null);
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(2, 1);
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 GrandParent
test of Parent
test of Son
使用invokespecial這種方式也有局限,只能從子類調用。否則報錯:
.setJsonFactory(JSON_FACTORY).setClientSecrets(clientSecrets)
.addRefreshListener(new CredentialStoreRefreshListener(userID, new DBCredentialStore())).build()
.setAccessToken(accessToken).setRefreshToken(refreshToken)
同時Builder類設置為static也是對Item 22:Favor static member classes over nonstatic的實踐
一 基本流程
使用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類中的
二 需要參數的情況
有些業務需要用戶傳參數,直接傳參數給A,再試圖在B中獲取是不行的!B類中只能獲取某些固定的參數,如code。要想傳用戶參數,我們可以在A中先獲取,把幾個參數組裝為json格式字符串(還可以繼續base64編碼),把這個字符串作為state的值,再重定向到授權頁面,同意后state參數可以傳到B類,取值解析json字符串(或先base64解碼),得到參數。
由于API中AuthorizationCodeRequestUrl有處理state的方法,而AbstractAuthorizationCodeServlet已經直接封裝,為了使用setState,直接在A類中繼承HttpServlet重寫service方法,復制大部分AbstractAuthorizationCodeServlet的內容,稍作修改:
三 關于refresh token
默認情況下,用戶授權之后token會有一個小時的有效期,之后你可以通過refresh token再重新獲取token。所以,如果不需要用戶再次授權,可以在第一次,保存好token、refresh token、ExpirationTime。實例中用了JDO來實現,自己如果使用數據庫保存,可類似寫一個類實現CredentialStore類。使用的時候,現在數據庫中取出,再創建credential,如:
.setJsonFactory(JSON_FACTORY).setClientSecrets(clientSecrets)
.addRefreshListener(new CredentialStoreRefreshListener(userID, new DBCredentialStore())).build()
.setAccessToken(accessToken).setRefreshToken(refreshToken)
.setExpirationTimeMilliseconds(expirationTimeMilliseconds);
在無效的情況下,Listener會自動去用refresh token請求。
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;
}
}
}
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中有一些注解,可以修改,不細說。
有兩種SOAP message風格,document 和RPC,他們定義了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的生成。