1
2
3
4
5 package gboat2.cxf.utils;
6
7 import gboat2.base.bridge.exception.DefaultGboatNestedException;
8 import gboat2.base.bridge.util.json.JsonUtil;
9 import gboat2.base.bridge.util.xml.JAXBUtil;
10
11 import java.util.ArrayList;
12 import java.util.LinkedHashMap;
13 import java.util.List;
14 import java.util.Map;
15
16 import javax.xml.bind.annotation.XmlRootElement;
17 import javax.xml.namespace.QName;
18
19 import org.apache.commons.collections.MapUtils;
20 import org.apache.commons.lang3.ArrayUtils;
21 import org.apache.commons.lang3.ClassUtils;
22 import org.apache.cxf.common.jaxb.JAXBUtils;
23 import org.apache.cxf.common.jaxb.JAXBUtils.IdentifierType;
24 import org.apache.cxf.endpoint.Client;
25 import org.apache.cxf.endpoint.Endpoint;
26 import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
27 import org.apache.cxf.service.model.BindingInfo;
28 import org.apache.cxf.service.model.BindingMessageInfo;
29 import org.apache.cxf.service.model.BindingOperationInfo;
30 import org.apache.cxf.service.model.MessagePartInfo;
31 import org.apache.cxf.transport.http.HTTPConduit;
32 import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35 import org.springframework.beans.BeanUtils;
36 import org.springframework.beans.BeansException;
37 import org.springframework.util.Assert;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class CXFUtil {
70
71 private final static Logger logger = LoggerFactory.getLogger(CXFUtil.class);
72 private final static int CONFIGURE_CLIENT_SIZE = 999999999;
73
74
75
76
77 private CXFUtil() {
78 }
79
80
81
82
83
84
85
86 public static Client createJaxWsDynamicClient(String wsdlUrl){
87 return createJaxWsDynamicClient(wsdlUrl, JaxWsDynamicClientFactory.class.getClassLoader());
88 }
89
90
91
92
93
94
95
96
97
98 public static Client createJaxWsDynamicClient(String wsdlUrl, ClassLoader classLoader) {
99
100 HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
101 httpClientPolicy.setAllowChunking(false);
102 httpClientPolicy.setChunkingThreshold(CONFIGURE_CLIENT_SIZE);
103
104
105 Client client = JaxWsDynamicClientFactory.newInstance().createClient(wsdlUrl, classLoader);
106 ((HTTPConduit) client.getConduit()).setClient(httpClientPolicy);
107 return client;
108 }
109
110
111
112
113
114
115
116 public static BindingOperationInfo getBindingOperationInfo(Client client, String operation){
117 Endpoint endpoint = client.getEndpoint();
118 BindingInfo bindingInfo = endpoint.getEndpointInfo().getBinding();
119 QName opName = new QName(endpoint.getService().getName().getNamespaceURI(), operation);
120 BindingOperationInfo boi = bindingInfo.getOperation(opName);
121 if (boi == null) {
122 for (BindingOperationInfo operationInfo : bindingInfo.getOperations()) {
123 if (operation.equals(operationInfo.getName().getLocalPart())) {
124 return operationInfo;
125 }
126 }
127 }
128 return boi;
129 }
130
131
132
133
134
135
136 public static Map<String, Class<?>> getInputParameters(BindingOperationInfo operationInfo) {
137 return getParameters(operationInfo, true);
138 }
139
140
141
142
143
144
145 public static Map<String, Class<?>> getOutputParameters(BindingOperationInfo operationInfo) {
146 return getParameters(operationInfo, false);
147 }
148
149
150
151
152
153
154
155 private static Map<String, Class<?>> getParameters(BindingOperationInfo boi, boolean input) {
156 BindingOperationInfo unWrappedBoi = boi.isUnwrapped() ? boi : boi.getUnwrappedOperation();
157 BindingMessageInfo bmi = (input ? unWrappedBoi.getInput() : unWrappedBoi.getOutput());
158 List<MessagePartInfo> messageParts = bmi.getMessageParts();
159 Map<String, Class<?>> result = new LinkedHashMap<String, Class<?>>(messageParts.size());
160 for (MessagePartInfo mpi : messageParts) {
161 result.put(mpi.getName().getLocalPart(), mpi.getTypeClass());
162 }
163 return result;
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177 public static Object[] invokeWebService(String wsdlUrl, String operation, Object... parameters) {
178 return invokeWebService(wsdlUrl, operation, JaxWsDynamicClientFactory.class.getClassLoader(), parameters);
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192 public static Object[] invokeWebService(String wsdlUrl, String operation,
193 ClassLoader classLoader, Object... parameters) {
194
195 Client client = createJaxWsDynamicClient(wsdlUrl, classLoader);
196
197 return invokeWebService(client, operation, parameters);
198 }
199
200
201
202
203
204
205
206
207 public static Object[] invokeWebService(Client client, String operation, Object... parameters) {
208 try {
209 BindingOperationInfo boi = getBindingOperationInfo(client, operation);
210 if(boi == null)
211 throw new DefaultGboatNestedException(
212 "No operation was found with the name [" + operation + "] of namespace "
213 + client.getEndpoint().getService().getName().getNamespaceURI());
214
215 if(!boi.isUnwrapped()) {
216 boi = boi.getUnwrappedOperation();
217 }
218
219 Map<String,Class<?>> inputParamInfoMap = getInputParameters(boi);
220 if(ArrayUtils.isNotEmpty(parameters) && MapUtils.isNotEmpty(inputParamInfoMap)) {
221 List<Class<?>> needTypes = new ArrayList<Class<?>>(inputParamInfoMap.values());
222 Class<?> needType = null;
223 Class<?> actualType = null;
224 for (int i = 0, size = needTypes.size(); i < size; i++) {
225
226 if(i >= parameters.length)
227 break;
228
229
230 if(parameters[i] == null)
231 continue;
232
233 needType = needTypes.get(i);
234 actualType = parameters[i].getClass();
235
236 if(ClassUtils.isPrimitiveOrWrapper(actualType) || needType.isAssignableFrom(actualType))
237 continue;
238
239
240 Object obj = null;
241 try {
242 obj = needType.newInstance();
243 BeanUtils.copyProperties(parameters[i], obj);
244 } catch (BeansException e) {
245 logger.warn(
246 "通过 CXF 调用 WebService [{}] 时,将第 [{}] 个参数 [{}] 的属性值复制给目标类型的对象 [{}] 失败,将改用 JSON 转换的方式将其转换为目标类型。",
247 boi, i, actualType, needType);
248
249 String json = JsonUtil.object2Json(parameters[i]);
250 obj = JsonUtil.json2Object(json, needType);
251 }
252 parameters[i] = obj;
253 }
254 }
255
256
257 return client.invoke(boi, parameters);
258 } catch (Exception e) {
259 throw new DefaultGboatNestedException("使用 CXF 动态调用 WebService 服务 [" + operation + "] 失败", e);
260 }
261 }
262
263
264
265
266
267
268
269
270
271
272 public static Object[] invokeWrappedWebService(String wsdlUrl, Object parameter){
273 return invokeWrappedWebService(wsdlUrl, parameter, JaxWsDynamicClientFactory.class.getClassLoader());
274 }
275
276
277
278
279
280
281
282
283
284
285
286
287 public static Object[] invokeWrappedWebService(String wsdlUrl, Object parameter, ClassLoader classLoader){
288
289 Client client = createJaxWsDynamicClient(wsdlUrl, classLoader);
290
291 return invokeWrappedWebService(client, parameter);
292 }
293
294
295
296
297
298
299
300
301
302
303 public static Object[] invokeWrappedWebService(Client client, Object parameter) {
304 Assert.notNull(parameter, "使用经过 CXF 包装后客户端调用 WebService 失败,原因:传入的参数不能为 null");
305
306 Class<?> paramType = parameter.getClass();
307 XmlRootElement xmlRootElement = paramType.getAnnotation(XmlRootElement.class);
308 Assert.notNull(xmlRootElement, "使用经过 CXF 包装后客户端调用 WebService 失败,原因:传入的参数类型 [" + paramType + "] 必须有 javax.xml.bind.annotation.XmlRootElement 注解");
309
310 String operation = xmlRootElement.name();
311 if("##default".equals(operation)) {
312 operation = paramType.getSimpleName();
313 }
314
315 try {
316 BindingOperationInfo boi = getBindingOperationInfo(client, operation);
317 if(boi == null)
318 throw new DefaultGboatNestedException(
319 "No operation was found with the name [" + operation + "] of namespace " + client.getEndpoint().getService().getName().getNamespaceURI());
320
321 QName qname = boi.getName();
322 String packageName = JAXBUtils.namespaceURIToPackage(qname.getNamespaceURI());
323 String simpleClassName = JAXBUtils.nameToIdentifier(qname.getLocalPart(), IdentifierType.CLASS);
324 String className = packageName + "." + simpleClassName;
325
326
327 Class<?> needType = Thread.currentThread().getContextClassLoader().loadClass(className);
328 if(!needType.isAssignableFrom(paramType)){
329
330 parameter = JAXBUtil.castClone(parameter, needType);
331 }
332
333
334 return client.invoke(boi, parameter);
335 } catch (Exception e) {
336 throw new DefaultGboatNestedException("使用经过 CXF 包装后客户端调用 WebService [" + operation + "] 失败", e);
337 }
338 }
339
340 }