1 package org.apache.beehive.wsm.model.jsr181; 2 3 20 21 import org.apache.beehive.wsm.model.*; 22 import org.apache.beehive.wsm.model.java.JavaMethodInfo; 23 import org.apache.beehive.wsm.model.java.JavaTypeInfo; 24 import org.w3c.dom.Element ; 25 import org.w3c.dom.Node ; 26 import org.w3c.dom.NodeList ; 27 28 import javax.jws.HandlerChain; 29 import javax.jws.WebMethod; 30 import javax.jws.WebService; 31 import javax.jws.soap.SOAPBinding; 32 import javax.jws.soap.SOAPMessageHandler; 33 import javax.jws.soap.SOAPMessageHandlers; 34 import javax.xml.parsers.DocumentBuilderFactory ; 35 import java.io.File ; 36 import java.lang.annotation.Annotation ; 37 import java.net.MalformedURLException ; 38 import java.net.URL ; 39 import java.util.*; 40 41 44 public class Jsr181TypeMetadataImpl implements BeehiveWsTypeMetadata, java.io.Serializable { 45 46 private static final long serialVersionUID = 1L; 47 48 private String wsName; 49 private String wsServiceName; 50 private String wsWsdlLocation; 51 private String wsTargetNamespace; 52 private String wsEndpointInterface; 53 private Map<String , BeehiveWsMethodMetadata> methodMap = 54 new HashMap<String , BeehiveWsMethodMetadata>(); 55 private Set<BeehiveWsMethodMetadata> noDuplicateMethods; 56 private BeehiveWsSOAPBindingInfo soapBinding; 57 private String hcFileName; 58 private String hcName; 59 private List <BeehiveWsSOAPMessageHandlerInfo> soapHandlers = 60 new ArrayList<BeehiveWsSOAPMessageHandlerInfo>(); 61 private String siValue; 62 private String className; 63 private File baseLocation; 64 65 68 public Jsr181TypeMetadataImpl() { 69 } 71 72 79 public Jsr181TypeMetadataImpl(JavaTypeInfo jt) { 80 81 super(); 82 83 if (null == jt) { 84 jt.logError("illegal java type info: <null>"); 85 return; 86 } 87 88 WebService webService = jt.getAnnotation(WebService.class); 90 if (null == webService) { 91 jt.logError("no @WebService annotation found"); 92 } 93 94 Collection<BeehiveWsMethodMetadata> webMethods = 96 new ArrayList<BeehiveWsMethodMetadata>(); 97 if (! jt.isInterface()) { 99 for (JavaMethodInfo jm : jt.getMethods()) { 100 if (null != jm.getAnnotation(WebMethod.class)) { 101 BeehiveWsMethodMetadata wsmm = new Jsr181MethodMetadataImpl(jm); 102 if (null == wsmm) { 103 jt.logError("illegal web method: " + jm.getMethodName()); 104 } 105 webMethods.add(wsmm); 106 } 107 } 108 } 109 if (webMethods.isEmpty()) { 111 for (JavaMethodInfo jm : jt.getMethods()) { 112 BeehiveWsMethodMetadata wsmm = new Jsr181MethodMetadataImpl(jm); 113 webMethods.add(wsmm); 114 } 115 } 116 117 Collection<Annotation > annotations = jt.getAnnotations(); 119 if ((null == annotations) || (null == webMethods)) { 120 jt.logError("no annotations or web methods found"); 121 } 122 123 className = jt.getName(); 125 if ((null == className) || (0 == className.length())) { 126 jt.logError("web service class is null"); 127 } 128 baseLocation = jt.getLocation(); 129 130 if (jt.isFinal() || ! jt.isPublic()) { 132 jt.logError("@WebService class must be public but not final"); 133 } 134 if (jt.hasFinalize()) { 135 jt.logError("web service class must not declare method: finalize()"); 136 } 137 if (jt.isInterface()) { 138 if (null != webService.endpointInterface() && 0 < webService.endpointInterface().trim().length()) { 139 jt.logError("@WebService.endpointInterface not allowed on interfaces"); 140 } 141 if (null != webService.serviceName() && 0 < webService.serviceName().trim().length()) { 142 jt.logError("@WebService.serviceName not allowed on interfaces"); 143 } 144 } 145 else { 146 if (jt.isAbstract()) { 147 jt.logError("service implementation bean must not be abstract"); 148 } 149 if (! jt.hasDefaultConstructor()) { 150 jt.logError("service implementation bean must have default constructor"); 151 } 152 } 153 if (null != jt.getAnnotation(SOAPMessageHandlers.class) && null != jt.getAnnotation(HandlerChain.class)) { 154 jt.logError("Illegal combination of @SOAPMessageHandlers and @HandlerChain"); 155 } 156 String wsdlLocation = webService.wsdlLocation(); 157 if (null != wsdlLocation && 0 < wsdlLocation.trim().length()) { 158 try { 159 findResource(wsdlLocation.trim(), baseLocation).openStream(); 160 } 161 catch (Throwable t) { 162 jt.logError("wsdlLocation does not exist: " + wsdlLocation); 163 } 164 } 165 166 initFromAnnotation(webService); 168 169 for (Annotation a : annotations) { 171 172 if (a.annotationType() == javax.jws.HandlerChain.class) { 174 initFromAnnotation((javax.jws.HandlerChain) a); 175 } 176 177 else if (a.annotationType() == javax.jws.soap.SOAPBinding.class) { 179 initFromAnnotation((javax.jws.soap.SOAPBinding) a); 180 } 181 182 else if (a.annotationType() == javax.jws.soap.SOAPMessageHandlers.class) { 184 initFromAnnotation((javax.jws.soap.SOAPMessageHandlers) a); 185 } 186 187 else if (a.annotationType() == javax.jws.WebService.class) { 189 } 192 193 else { 195 jt.logError("found unsupported annotation: " + a.annotationType().getName()); 196 } 197 } 198 199 for (BeehiveWsMethodMetadata wsmm : webMethods) { 201 String wrTargetNamespace = wsmm.getWrTargetNamespace(); 203 if ((null == wrTargetNamespace) || (0 == wrTargetNamespace.length())) { 204 wsmm.setWrTargetNamespace(getWsTargetNamespace()); 205 } 206 207 for (BeehiveWsParameterMetadata wspm : wsmm.getParams()) { 209 String wpTargetNamespace = wspm.getWpTargetNamespace(); 210 if ((null == wpTargetNamespace) || (0 == wpTargetNamespace.length())) { 211 wspm.setWpTargetNamespace(getWsTargetNamespace()); 212 } 213 } 214 215 try { 217 addMethod(wsmm); 218 } 219 catch (ValidationException e) { 220 jt.logError("cannot add web method to metadata: " + wsmm.getJavaMethodName()); 221 } 222 } 223 } 224 225 protected void initFromAnnotation(WebService annotation) { 226 227 if (null == annotation) { 228 return; 229 } 230 231 wsEndpointInterface = annotation.endpointInterface().trim(); 233 234 setWsName(annotation.name()); 235 setWsTargetNamespace(annotation.targetNamespace()); 236 setWsWsdlLocation(annotation.wsdlLocation()); 237 setWsServiceName(annotation.serviceName()); 238 setWsEndpointInterface(annotation.endpointInterface()); 239 240 242 String name = className; 244 if (-1 < name.indexOf('.')) { 245 int index = name.lastIndexOf('.'); 246 name = name.substring(index + 1); 247 } 248 if (0 == getWsName().length()) { 249 setWsName(name); 250 } 251 252 String serviceName = className; 254 if (-1 < serviceName.indexOf('.')) { 255 int index = serviceName.lastIndexOf('.'); 256 serviceName = serviceName.substring(index + 1); 257 } 258 if (0 == getWsServiceName().length()) { 259 setWsServiceName(serviceName + "Service"); 260 } 261 262 if (0 == getWsTargetNamespace().length()) { 264 setWsTargetNamespace(getTargetNamespace(className)); 265 } 266 } 267 268 private void initFromAnnotation(SOAPBinding annotation) { 269 270 if (null == annotation) { 271 return; 272 } 273 274 setSoapBinding(new SOAPBindingInfo(annotation)); 276 277 BeehiveWsSOAPBindingInfo sbi = getSoapBinding(); 279 if (null == sbi) { 280 throw new IllegalArgumentException ("illegal SOAPBinding annotation on WebService class:\n\t" + sbi); 281 } 282 283 } 285 286 private void initFromAnnotation(HandlerChain annotation) { 287 288 if (null == annotation) { 289 return; 290 } 291 292 if (! getSoapHandlers().isEmpty()) { 293 throw new IllegalArgumentException ("@SOAPMessageHandlers and @HandlerChain are mutually exclusive"); 294 } 295 296 String hcPath = annotation.file(); 297 String hcName = annotation.name(); 298 299 setHcName(hcName); 300 setHcFileName(hcPath); 301 302 try { 303 configureHandlerChain(hcPath, hcName); 304 } 305 catch (Throwable t) { 306 throw new RuntimeException (t.getMessage()); 307 } 308 } 309 310 private void initFromAnnotation(SOAPMessageHandlers annotation) { 311 312 if (null == annotation) { 313 return; 314 } 315 316 if (null != getHcFileName()) { 317 throw new IllegalArgumentException ("@SOAPMessageHandlers and @HandlerChain are mutually exclusive"); 318 } 319 320 for (SOAPMessageHandler soapMessageHandler : annotation.value()) { 321 BeehiveWsSOAPMessageHandlerInfo smhi = new SOAPMessageHandlerInfo(soapMessageHandler); 322 addSOAPHandler(smhi); 324 } 325 } 326 327 328 private void configureHandlerChain(String handlerChainConfigPath, String handlerChainName) 329 throws Exception 330 { 331 URL handlerChainConfigURL = findResource(handlerChainConfigPath, baseLocation); 333 if (null == handlerChainConfigURL) { 334 throw new Exception ("@HandlerChain: cannot resolve relative URL: " + handlerChainConfigPath + "(base directory: " + baseLocation + ")"); 335 } 336 337 initHandlersFromChainConfig(handlerChainConfigURL, handlerChainName); 339 } 340 341 351 private URL findResource(String resourcePath, File basePath) { 352 353 URL resourceURL = null; 354 355 if (null == resourcePath || 0 == resourcePath.length()) { 357 return null; 358 } 359 360 if (resourcePath.startsWith("http://") || resourcePath.startsWith("file:/")) { 362 try { 363 resourceURL = new URL (resourcePath); 364 return resourceURL; 365 } 366 catch (MalformedURLException e) { 367 return null; 368 } 369 } 370 371 if ((null == basePath) || (! basePath.exists())) { 373 return null; 374 } 375 if (resourcePath.startsWith("/")) { 376 String base = basePath.toString(); 377 String temp = className; 378 int lastIdx = className.lastIndexOf('.'); 379 if (0 >= lastIdx) { 380 return null; 381 } 382 temp = temp.substring(0, lastIdx).replace('.', File.separatorChar); 383 if (! base.endsWith(temp)) { 384 return null; 385 } 386 temp = base.substring(0, base.length() - temp.length()); 387 try { 388 resourceURL = new File (temp, resourcePath).toURL(); 389 } 390 catch (MalformedURLException e) { 391 return null; 392 } 393 } 394 else { 395 try { 396 resourceURL = new File (basePath, resourcePath).toURL(); 397 } 398 catch (MalformedURLException e) { 399 return null; 400 } 401 } 402 403 return resourceURL; 404 } 405 406 413 public void initHandlersFromChainConfig(URL chainConfigURL, String chainName) 414 throws Exception 415 { 416 if (! getSoapHandlers().isEmpty()) { 418 throw new Exception ("@HandlerChain: annotation doesn't allow for @SOAPMessageHandlers"); 419 } 420 if (null == chainConfigURL || null == chainName) { 421 throw new Exception ("@HandlerChain: URL for handler-chain config required"); 422 } 423 424 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 426 factory.setNamespaceAware(true); 427 factory.setIgnoringComments(true); 428 429 431 NodeList handlerChainNodes = factory.newDocumentBuilder().parse(chainConfigURL.openStream()).getElementsByTagName("handler-chain"); 432 for (int j = 0; j < handlerChainNodes.getLength(); j++) { 433 Node handlerChainNode = handlerChainNodes.item(j); 434 if (handlerChainNode.getNodeType() == Node.ELEMENT_NODE) { 435 Element chainElement = (Element ) handlerChainNode; 436 NodeList chainNames = chainElement.getElementsByTagName("handler-chain-name"); 437 438 if (chainNames.getLength() > 0 && chainName.equals(chainNames.item(0).getFirstChild().getNodeValue())) { 441 NodeList handlers = chainElement.getElementsByTagName("handler"); 442 for (int k = 0; k < handlers.getLength(); k++) { 443 processHandlerNode(handlers.item(k)); 444 } 445 } 446 } 447 } 448 } 449 450 454 private void processHandlerNode(Node handlerNode) 455 throws Exception 456 { 457 if (handlerNode.hasChildNodes()) { 458 String handlerName = null; 459 String handlerClassName = null; 460 Map<String , String > initParams = new HashMap<String , String >(); 461 Collection<String > roles = new ArrayList<String >(); 462 Collection<String > headers = new ArrayList<String >(); 463 Node currentChild = handlerNode.getFirstChild(); 464 while (currentChild != null) { 465 String nodeName = currentChild.getNodeName(); 466 if (nodeName.endsWith("handler-name")) { 467 handlerName = currentChild.getFirstChild().getNodeValue(); 468 } 469 else if (nodeName.endsWith("handler-class")) { 470 handlerClassName = currentChild.getFirstChild().getNodeValue(); 471 } 472 else if (nodeName.endsWith("soap-role")) { 473 roles.add(currentChild.getFirstChild().getNodeValue()); 474 } 475 else if (nodeName.endsWith("soap-header")) { 476 headers.add(currentChild.getFirstChild().getNodeValue()); 477 } 478 else if (nodeName.endsWith("init-param")) { 479 nodeName = currentChild.getFirstChild().getNodeName(); 480 if (nodeName.endsWith("param-name")) { 481 initParams.put( 482 currentChild.getFirstChild().getNodeValue(), 483 currentChild.getLastChild().getNodeValue()); 484 } 485 else if (nodeName.endsWith("param-value")) { 486 initParams.put( 487 currentChild.getLastChild().getNodeValue(), 488 currentChild.getFirstChild().getNodeValue() 489 ); 490 } 491 } 492 currentChild = currentChild.getNextSibling(); 493 } 494 495 addSOAPHandler(new SOAPMessageHandlerInfo( 496 handlerClassName, 497 handlerName, 498 initParams, 499 roles, 500 headers)); 501 } 502 } 503 504 507 public void validate() { 508 } 510 511 514 public String getHcFileName() { 515 return hcFileName; 516 } 517 518 521 public void setHcFileName(String hcFileName) { 522 this.hcFileName = hcFileName; 523 } 524 525 528 public String getHcName() { 529 return hcName; 530 } 531 532 535 public void setHcName(String hcName) { 536 this.hcName = hcName; 537 } 538 539 540 543 public String getSiValue() { 544 return siValue; 545 } 546 547 550 public void setSiValue(String siValue) { 551 this.siValue = siValue; 552 } 553 554 557 public BeehiveWsSOAPBindingInfo getSoapBinding() { 558 if (soapBinding == null) { 559 soapBinding = new SOAPBindingInfo(); 560 } 561 return soapBinding; 562 } 563 564 567 public void setSoapBinding(BeehiveWsSOAPBindingInfo soapBinding) { 568 this.soapBinding = soapBinding; 569 } 570 571 574 public String getWsName() { 575 return wsName; 576 } 577 578 581 public void setWsName(String wsName) { 582 this.wsName = wsName; 583 } 584 585 588 public String getWsServiceName() { 589 return wsServiceName; 590 } 591 592 595 public void setWsServiceName(String wsServiceName) { 596 this.wsServiceName = wsServiceName; 597 } 598 599 602 public String getWsTargetNamespace() { 603 return wsTargetNamespace; 604 } 605 606 609 public void setWsTargetNamespace(String wsTargetNamespace) { 610 this.wsTargetNamespace = wsTargetNamespace; 611 } 612 613 614 public String [] getTargetNamespaceParts() { 615 String namespace=getWsTargetNamespace().substring(7, getWsTargetNamespace().length()); 617 String [] beforeTranspose = namespace.split("[\\./]"); 618 String [] res = new String [beforeTranspose.length]; 619 for(int i=0; i<res.length; i++) 620 res[i] = beforeTranspose[res.length - i - 1]; 621 return res; 622 } 623 624 627 public String getWsEndpointInterface() { 628 return wsEndpointInterface; 629 } 630 631 634 public void setWsEndpointInterface(String wsEndpointInterface) { 635 this.wsEndpointInterface = wsEndpointInterface; 636 } 637 638 641 public String getWsWsdlLocation() { 642 return wsWsdlLocation; 643 } 644 645 648 public void setWsWsdlLocation(String wsWsdlLocation) { 649 this.wsWsdlLocation = wsWsdlLocation; 650 } 651 652 655 public Collection<BeehiveWsMethodMetadata> getMethods() { 656 if (noDuplicateMethods == null) { 657 noDuplicateMethods = Collections 658 .unmodifiableSet(new HashSet<BeehiveWsMethodMetadata> 659 (methodMap.values())); 660 } 661 return noDuplicateMethods; 662 } 663 664 public BeehiveWsMethodMetadata getMethod(String methodName, 665 Class ... paramTypes) { 666 String sig = createCompleteMethodSignature(methodName, paramTypes); 667 668 BeehiveWsMethodMetadata meta = methodMap.get(sig); 669 if (meta == null) { 670 676 meta = methodMap.get(methodName + '('+ paramTypes.length + ')'); 677 } 678 return meta; 679 } 680 681 public void addMethod(BeehiveWsMethodMetadata method) 682 throws ValidationException { 683 684 noDuplicateMethods = null; 687 List <? extends BeehiveWsParameterMetadata> params = method.getParams(); 688 Class [] paramTypes = new Class [params.size()]; 689 int j = 0; 690 for (BeehiveWsParameterMetadata param : params) { 691 Class javaType = param.getJavaType(); 692 if (null == javaType) { 693 throw new ValidationException("<null> is not a valid parameter class"); 694 } 695 paramTypes[j++] = javaType; 696 } 697 String opName = method.getWmOperationName(); 698 String sig = createCompleteMethodSignature(opName, paramTypes); 699 700 if (methodMap.containsKey(sig)) { 701 throw new ValidationException(sig + " is already present in this Web Service and duplicate methods are not permitted"); 702 } 703 else if (SOAPBinding.Style.DOCUMENT.equals(getSoapBinding().getStyle()) && methodMap.containsKey(opName)) { 704 throw new ValidationException("document-style does not allow duplicate methods: " + opName); 705 } 706 else { 707 methodMap.put(sig, method); 708 methodMap.put(opName + '(' + paramTypes.length + ')', method); 709 } 710 } 711 712 public List <? extends BeehiveWsSOAPMessageHandlerInfo> getSoapHandlers() { 713 return Collections.unmodifiableList(soapHandlers); 714 } 715 716 public void addSOAPHandler(BeehiveWsSOAPMessageHandlerInfo soapHandler) { 717 soapHandlers.add(soapHandler); 718 } 719 720 public String getClassName() { 721 return className; 722 } 723 724 public void setClassName(String className) { 725 this.className = className; 726 } 727 728 private String getTargetNamespace(String fqClassName) { 729 if ((null == fqClassName) || (0 == fqClassName.length())) { 730 return fqClassName; 731 } 732 String [] tokens = fqClassName.split("\\."); 733 String targetNamespace = tokens[0]; 734 for (int i = 1; i <= tokens.length - 2; i++) { 735 targetNamespace = tokens[i] + "." + targetNamespace; 736 } 737 return "http://" + targetNamespace; 738 } 739 740 private String createCompleteMethodSignature(String name, 742 Class ... paramTypes) { 743 744 StringBuilder sb = new StringBuilder (name); 745 sb.append('('); 746 boolean firstParam = true; 747 if (paramTypes != null) { 748 for (Class type : paramTypes) { 749 if (firstParam) { 750 firstParam = false; 751 } 752 else { 753 sb.append(','); 754 } 755 sb.append(type.getName()); 756 } 757 } 758 sb.append(')'); 759 return sb.toString(); 760 } 761 762 766 public void merge(JavaTypeInfo jt) throws Exception { 767 768 String myEndpointInterface = getWsEndpointInterface(); 770 if (null != myEndpointInterface && 0 < myEndpointInterface.length()) 771 throw new ValidationException("service endpoint interface can't reference another service endpoint interface: " + myEndpointInterface); 772 773 BeehiveWsTypeMetadata sibObjectModel = new Jsr181TypeMetadataImpl(jt); 775 String omEndpointInterface = sibObjectModel.getWsEndpointInterface(); 776 if (null == omEndpointInterface || 0 >= omEndpointInterface.length() || ! omEndpointInterface.equals(getClassName())) 777 throw new Exception ("Internal error: object model for " + sibObjectModel.getClassName() + " does not reference endpoint interface "+ omEndpointInterface); 778 779 if (null != sibObjectModel.getWsWsdlLocation() && 0 < sibObjectModel.getWsWsdlLocation().length()) { 781 throw new Exception ("implementation bean must not reference a service endpoint interface and a WSDL location at the same time"); 782 } 783 784 setWsServiceName(sibObjectModel.getWsServiceName()); 785 setWsEndpointInterface(sibObjectModel.getWsEndpointInterface()); 786 787 setClassName(sibObjectModel.getClassName()); 788 789 validateContract(jt); 791 } 792 793 798 protected void validateContract(JavaTypeInfo jt) throws ValidationException { 799 800 Collection<BeehiveWsMethodMetadata> implementedMethods = new HashSet<BeehiveWsMethodMetadata>(); 802 for (JavaMethodInfo jm : jt.getMethods()) { 803 try { 804 implementedMethods.add(new Jsr181MethodMetadataImpl(jm)); 805 } 806 catch (Throwable t) { 807 throw new ValidationException("invalid method declaration found: " + jt.getName() + ": " + jm.getMethodName()); 808 } 809 } 810 811 for (BeehiveWsMethodMetadata declaredMethod : getMethods()) { 813 boolean implementationFound = false; 814 for (BeehiveWsMethodMetadata implementedMethod : implementedMethods) { 815 if (implementedMethod.equals(declaredMethod)) { 816 implementationFound = true; 817 break; 818 } 819 } 820 if (! implementationFound) { 821 throw new ValidationException("method not implemented by " + jt.getName() + ": " + declaredMethod); 822 } 823 } 824 } 825 } 826 | Popular Tags |