1 /*
2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.xml.internal.ws.handler;
27 
28 import com.sun.xml.internal.ws.api.BindingID;
29 import com.sun.xml.internal.ws.api.WSBinding;
30 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
31 import com.sun.xml.internal.ws.transport.http.DeploymentDescriptorParser;
32 import com.sun.xml.internal.ws.util.HandlerAnnotationInfo;
33 import com.sun.xml.internal.ws.util.JAXWSUtils;
34 import com.sun.xml.internal.ws.util.UtilException;
35 
36 import javax.annotation.PostConstruct;
37 import javax.xml.namespace.QName;
38 import javax.xml.stream.XMLStreamConstants;
39 import javax.xml.stream.XMLStreamReader;
40 import javax.xml.ws.handler.Handler;
41 import javax.xml.ws.handler.PortInfo;
42 import java.lang.reflect.Method;
43 import java.util.ArrayList;
44 import java.util.HashSet;
45 import java.util.List;
46 import java.util.Set;
47 import java.util.StringTokenizer;
48 import java.util.logging.Logger;
49 
50 
51 public class HandlerChainsModel {
52     private static final Logger logger = Logger.getLogger(
53             com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".util");
54 
55     private Class annotatedClass;
56     private List<HandlerChainType> handlerChains;
57     private String id;
58     /** Creates a new instance of HandlerChains */
HandlerChainsModel(Class annotatedClass)59     private HandlerChainsModel(Class annotatedClass) {
60         this.annotatedClass = annotatedClass;
61     }
62 
getHandlerChain()63     private List<HandlerChainType> getHandlerChain() {
64         if (handlerChains == null) {
65             handlerChains = new ArrayList<HandlerChainType>();
66         }
67         return handlerChains;
68     }
69 
getId()70     public String getId() {
71         return id;
72     }
73 
setId(String value)74     public void setId(String value) {
75         this.id = value;
76     }
77     /**
78      * reader should be on <handler-chains> element
79      */
parseHandlerConfigFile(Class annotatedClass, XMLStreamReader reader)80     public static HandlerChainsModel parseHandlerConfigFile(Class annotatedClass, XMLStreamReader reader) {
81         ensureProperName(reader,QNAME_HANDLER_CHAINS);
82         HandlerChainsModel handlerModel = new HandlerChainsModel(annotatedClass);
83         List<HandlerChainType> hChains = handlerModel.getHandlerChain();
84         XMLStreamReaderUtil.nextElementContent(reader);
85 
86         while (reader.getName().equals(QNAME_HANDLER_CHAIN)) {
87             HandlerChainType hChain = new HandlerChainType();
88             XMLStreamReaderUtil.nextElementContent(reader);
89 
90             if (reader.getName().equals(QNAME_CHAIN_PORT_PATTERN)) {
91                 QName portNamePattern = XMLStreamReaderUtil.getElementQName(reader);
92                 hChain.setPortNamePattern(portNamePattern);
93                 XMLStreamReaderUtil.nextElementContent(reader);
94             } else if (reader.getName().equals(QNAME_CHAIN_PROTOCOL_BINDING)) {
95                 String bindingList = XMLStreamReaderUtil.getElementText(reader);
96                 StringTokenizer stk = new StringTokenizer(bindingList);
97                 while(stk.hasMoreTokens()) {
98                     String token = stk.nextToken();
99                     // This will convert tokens into Binding URI
100                     hChain.addProtocolBinding(token);
101                 }
102                 XMLStreamReaderUtil.nextElementContent(reader);
103             } else if (reader.getName().equals(QNAME_CHAIN_SERVICE_PATTERN)) {
104                 QName serviceNamepattern = XMLStreamReaderUtil.getElementQName(reader);
105                 hChain.setServiceNamePattern(serviceNamepattern);
106                 XMLStreamReaderUtil.nextElementContent(reader);
107             }
108             List<HandlerType> handlers = hChain.getHandlers();
109             // process all <handler> elements
110             while (reader.getName().equals(QNAME_HANDLER)) {
111                 HandlerType handler = new HandlerType();
112 
113                 XMLStreamReaderUtil.nextContent(reader);
114                 if (reader.getName().equals(QNAME_HANDLER_NAME)) {
115                     String handlerName =
116                             XMLStreamReaderUtil.getElementText(reader).trim();
117                     handler.setHandlerName(handlerName);
118                     XMLStreamReaderUtil.nextContent(reader);
119                 }
120 
121                 // handler class
122                 ensureProperName(reader, QNAME_HANDLER_CLASS);
123                 String handlerClass =
124                         XMLStreamReaderUtil.getElementText(reader).trim();
125                 handler.setHandlerClass(handlerClass);
126                 XMLStreamReaderUtil.nextContent(reader);
127 
128                 // init params (ignored)
129                 while (reader.getName().equals(QNAME_HANDLER_PARAM)) {
130                     skipInitParamElement(reader);
131                 }
132 
133                 // headers (ignored)
134                 while (reader.getName().equals(QNAME_HANDLER_HEADER)) {
135                     skipTextElement(reader);
136                 }
137 
138                 // roles (not stored per handler)
139                 while (reader.getName().equals(QNAME_HANDLER_ROLE)) {
140                     List<String> soapRoles = handler.getSoapRoles();
141                     soapRoles.add(XMLStreamReaderUtil.getElementText(reader));
142                     XMLStreamReaderUtil.nextContent(reader);
143                 }
144 
145                 handlers.add(handler);
146 
147                 // move past </handler>
148                 ensureProperName(reader, QNAME_HANDLER);
149                 XMLStreamReaderUtil.nextContent(reader);
150             }
151 
152             // move past </handler-chain>
153             ensureProperName(reader, QNAME_HANDLER_CHAIN);
154             hChains.add(hChain);
155             XMLStreamReaderUtil.nextContent(reader);
156         }
157 
158         return handlerModel;
159     }
160 
161     /**
162      * <p>This method is called internally by HandlerAnnotationProcessor,
163      * and by
164      * {@link com.sun.xml.internal.ws.transport.http.DeploymentDescriptorParser}
165      * directly when it reaches the handler chains element in the
166      * descriptor file it is parsing.
167      * @param reader should be on <handler-chains> element
168      * @return A HandlerAnnotationInfo object that stores the
169      * handlers and roles.
170      */
171 
172 
173 
parseHandlerFile(XMLStreamReader reader, ClassLoader classLoader, QName serviceName, QName portName, WSBinding wsbinding)174     public static HandlerAnnotationInfo parseHandlerFile(XMLStreamReader reader,
175             ClassLoader classLoader, QName serviceName, QName portName,
176             WSBinding wsbinding) {
177         ensureProperName(reader,QNAME_HANDLER_CHAINS);
178         String bindingId = wsbinding.getBindingId().toString();
179         HandlerAnnotationInfo info = new HandlerAnnotationInfo();
180 
181         XMLStreamReaderUtil.nextElementContent(reader);
182 
183         List<Handler> handlerChain = new ArrayList<Handler>();
184         Set<String> roles = new HashSet<String>();
185 
186         while (reader.getName().equals(QNAME_HANDLER_CHAIN)) {
187 
188             XMLStreamReaderUtil.nextElementContent(reader);
189 
190             if (reader.getName().equals(QNAME_CHAIN_PORT_PATTERN)) {
191                 if (portName == null) {
192                     logger.warning("handler chain sepcified for port " +
193                             "but port QName passed to parser is null");
194                 }
195                 boolean parseChain = JAXWSUtils.matchQNames(portName,
196                         XMLStreamReaderUtil.getElementQName(reader));
197                 if (!parseChain) {
198                     skipChain(reader);
199                     continue;
200                 }
201                 XMLStreamReaderUtil.nextElementContent(reader);
202             } else if (reader.getName().equals(QNAME_CHAIN_PROTOCOL_BINDING)) {
203                 if (bindingId == null) {
204                     logger.warning("handler chain sepcified for bindingId " +
205                             "but bindingId passed to parser is null");
206                 }
207                 String bindingConstraint = XMLStreamReaderUtil.getElementText(reader);
208                 boolean skipThisChain = true;
209                 StringTokenizer stk = new StringTokenizer(bindingConstraint);
210                 List<String> bindingList = new ArrayList<String>();
211                 while(stk.hasMoreTokens()) {
212                     String tokenOrURI = stk.nextToken();
213                     /*
214                     Convert short-form tokens to API's binding ids
215                     Unknown token, Put it as it is
216                     */
217                     tokenOrURI = DeploymentDescriptorParser.getBindingIdForToken(tokenOrURI);
218                     String binding = BindingID.parse(tokenOrURI).toString();
219                     bindingList.add(binding);
220                 }
221                 if(bindingList.contains(bindingId)){
222                     skipThisChain = false;
223                 }
224 
225                 if (skipThisChain) {
226                     skipChain(reader);
227                     continue;
228                 }
229                 XMLStreamReaderUtil.nextElementContent(reader);
230             } else if (reader.getName().equals(QNAME_CHAIN_SERVICE_PATTERN)) {
231                 if (serviceName == null) {
232                     logger.warning("handler chain sepcified for service " +
233                             "but service QName passed to parser is null");
234                 }
235                 boolean parseChain = JAXWSUtils.matchQNames(
236                         serviceName,
237                         XMLStreamReaderUtil.getElementQName(reader));
238                 if (!parseChain) {
239                     skipChain(reader);
240                     continue;
241                 }
242                 XMLStreamReaderUtil.nextElementContent(reader);
243             }
244 
245             // process all <handler> elements
246             while (reader.getName().equals(QNAME_HANDLER)) {
247                 Handler handler;
248 
249                 XMLStreamReaderUtil.nextContent(reader);
250                 if (reader.getName().equals(QNAME_HANDLER_NAME)) {
251                     skipTextElement(reader);
252                 }
253 
254                 // handler class
255                 ensureProperName(reader, QNAME_HANDLER_CLASS);
256                 try {
257                     handler = (Handler) loadClass(classLoader,
258                             XMLStreamReaderUtil.getElementText(reader).trim()).newInstance();
259                 } catch (InstantiationException ie){
260                     throw new RuntimeException(ie);
261                 } catch (IllegalAccessException e) {
262                     throw new RuntimeException(e);
263                 }
264                 XMLStreamReaderUtil.nextContent(reader);
265 
266                 // init params (ignored)
267                 while (reader.getName().equals(QNAME_HANDLER_PARAM)) {
268                     skipInitParamElement(reader);
269                 }
270 
271                 // headers (ignored)
272                 while (reader.getName().equals(QNAME_HANDLER_HEADER)) {
273                     skipTextElement(reader);
274                 }
275 
276                 // roles (not stored per handler)
277                 while (reader.getName().equals(QNAME_HANDLER_ROLE)) {
278                     roles.add(XMLStreamReaderUtil.getElementText(reader));
279                     XMLStreamReaderUtil.nextContent(reader);
280                 }
281 
282                 // call @PostConstruct method on handler if present
283                 for (Method method : handler.getClass().getMethods()) {
284                     if (method.getAnnotation(PostConstruct.class) == null) {
285                         continue;
286                     }
287                     try {
288                         method.invoke(handler, new Object [0]);
289                         break;
290                     } catch (Exception e) {
291                         throw new RuntimeException(e);
292                     }
293                 }
294 
295                 handlerChain.add(handler);
296 
297                 // move past </handler>
298                 ensureProperName(reader, QNAME_HANDLER);
299                 XMLStreamReaderUtil.nextContent(reader);
300             }
301 
302             // move past </handler-chain>
303             ensureProperName(reader, QNAME_HANDLER_CHAIN);
304             XMLStreamReaderUtil.nextContent(reader);
305         }
306 
307         info.setHandlers(handlerChain);
308         info.setRoles(roles);
309         return info;
310     }
311 
getHandlersForPortInfo(PortInfo info)312     public HandlerAnnotationInfo getHandlersForPortInfo(PortInfo info){
313 
314         HandlerAnnotationInfo handlerInfo = new HandlerAnnotationInfo();
315         List<Handler> handlerClassList = new ArrayList<Handler>();
316         Set<String> roles = new HashSet<String>();
317 
318         for(HandlerChainType hchain : handlerChains) {
319             boolean hchainMatched = false;
320             if((!hchain.isConstraintSet()) ||
321                     JAXWSUtils.matchQNames(info.getServiceName(), hchain.getServiceNamePattern()) ||
322                     JAXWSUtils.matchQNames(info.getPortName(), hchain.getPortNamePattern()) ||
323                     hchain.getProtocolBindings().contains(info.getBindingID()) ){
324                 hchainMatched = true;
325 
326             }
327             if(hchainMatched) {
328                 for(HandlerType handler : hchain.getHandlers()) {
329                     try {
330                         Handler handlerClass = (Handler) loadClass(annotatedClass.getClassLoader(),
331                                 handler.getHandlerClass()).newInstance();
332                         callHandlerPostConstruct(handlerClass);
333                         handlerClassList.add(handlerClass);
334                     } catch (InstantiationException ie){
335                         throw new RuntimeException(ie);
336                     } catch (IllegalAccessException e) {
337                         throw new RuntimeException(e);
338                     }
339 
340                     roles.addAll(handler.getSoapRoles());
341                 }
342 
343             }
344         }
345 
346         handlerInfo.setHandlers(handlerClassList);
347         handlerInfo.setRoles(roles);
348         return handlerInfo;
349 
350     }
351 
loadClass(ClassLoader loader, String name)352     private static Class loadClass(ClassLoader loader, String name) {
353         try {
354             return Class.forName(name, true, loader);
355         } catch (ClassNotFoundException e) {
356             throw new UtilException(
357                     "util.handler.class.not.found",
358                     name);
359         }
360     }
361 
callHandlerPostConstruct(Object handlerClass)362     private static void callHandlerPostConstruct(Object handlerClass) {
363         // call @PostConstruct method on handler if present
364         for (Method method : handlerClass.getClass().getMethods()) {
365             if (method.getAnnotation(PostConstruct.class) == null) {
366                 continue;
367             }
368             try {
369                 method.invoke(handlerClass, new Object [0]);
370                 break;
371             } catch (Exception e) {
372                 throw new RuntimeException(e);
373             }
374         }
375     }
376 
skipChain(XMLStreamReader reader)377     private static void skipChain(XMLStreamReader reader) {
378         while (XMLStreamReaderUtil.nextContent(reader) !=
379                 XMLStreamConstants.END_ELEMENT ||
380                 !reader.getName().equals(QNAME_HANDLER_CHAIN)) {}
381         XMLStreamReaderUtil.nextElementContent(reader);
382     }
383 
skipTextElement(XMLStreamReader reader)384     private static void skipTextElement(XMLStreamReader reader) {
385         XMLStreamReaderUtil.nextContent(reader);
386         XMLStreamReaderUtil.nextElementContent(reader);
387         XMLStreamReaderUtil.nextElementContent(reader);
388     }
389 
skipInitParamElement(XMLStreamReader reader)390     private static void skipInitParamElement(XMLStreamReader reader) {
391         int state;
392         do {
393             state = XMLStreamReaderUtil.nextContent(reader);
394         } while (state != XMLStreamReader.END_ELEMENT ||
395                 !reader.getName().equals(QNAME_HANDLER_PARAM));
396         XMLStreamReaderUtil.nextElementContent(reader);
397     }
398 
ensureProperName(XMLStreamReader reader, QName expectedName)399     private static void ensureProperName(XMLStreamReader reader,
400             QName expectedName) {
401 
402         if (!reader.getName().equals(expectedName)) {
403             failWithLocalName("util.parser.wrong.element", reader,
404                     expectedName.getLocalPart());
405         }
406     }
407 
ensureProperName(XMLStreamReader reader, String expectedName)408     static void ensureProperName(XMLStreamReader reader, String expectedName) {
409         if (!reader.getLocalName().equals(expectedName)) {
410             failWithLocalName("util.parser.wrong.element", reader,
411                     expectedName);
412         }
413     }
414 
failWithLocalName(String key, XMLStreamReader reader, String arg)415     private static void failWithLocalName(String key,
416             XMLStreamReader reader, String arg) {
417         throw new UtilException(key,
418             Integer.toString(reader.getLocation().getLineNumber()),
419             reader.getLocalName(),
420             arg );
421     }
422 
423     public static final String PROTOCOL_SOAP11_TOKEN = "##SOAP11_HTTP";
424     public static final String PROTOCOL_SOAP12_TOKEN = "##SOAP12_HTTP";
425     public static final String PROTOCOL_XML_TOKEN = "##XML_HTTP";
426 
427     public static final String NS_109 =
428             "http://java.sun.com/xml/ns/javaee";
429     public static final QName QNAME_CHAIN_PORT_PATTERN =
430             new QName(NS_109, "port-name-pattern");
431     public static final QName QNAME_CHAIN_PROTOCOL_BINDING =
432             new QName(NS_109, "protocol-bindings");
433     public static final QName QNAME_CHAIN_SERVICE_PATTERN =
434             new QName(NS_109, "service-name-pattern");
435     public static final QName QNAME_HANDLER_CHAIN =
436             new QName(NS_109, "handler-chain");
437     public static final QName QNAME_HANDLER_CHAINS =
438             new QName(NS_109, "handler-chains");
439     public static final QName QNAME_HANDLER =
440             new QName(NS_109, "handler");
441     public static final QName QNAME_HANDLER_NAME =
442             new QName(NS_109, "handler-name");
443     public static final QName QNAME_HANDLER_CLASS =
444             new QName(NS_109, "handler-class");
445     public static final QName QNAME_HANDLER_PARAM =
446             new QName(NS_109, "init-param");
447     public static final QName QNAME_HANDLER_PARAM_NAME =
448             new QName(NS_109, "param-name");
449     public static final QName QNAME_HANDLER_PARAM_VALUE =
450             new QName(NS_109, "param-value");
451     public static final QName QNAME_HANDLER_HEADER =
452             new QName(NS_109, "soap-header");
453     public static final QName QNAME_HANDLER_ROLE =
454             new QName(NS_109, "soap-role");
455 
456     static class HandlerChainType {
457         //constraints
458         QName serviceNamePattern;
459         QName portNamePattern;
460         List<String> protocolBindings;
461 
462         // This flag is set if one of the above constraint is set on handler chain
463         boolean constraintSet = false;
464 
465         List<HandlerType> handlers;
466         String id;
467 
468 
469         /** Creates a new instance of HandlerChain */
HandlerChainType()470         public HandlerChainType() {
471             protocolBindings = new ArrayList<String>();
472         }
473 
setServiceNamePattern(QName value)474         public void setServiceNamePattern(QName value) {
475             this.serviceNamePattern = value;
476             constraintSet = true;
477         }
478 
getServiceNamePattern()479         public QName getServiceNamePattern() {
480             return serviceNamePattern;
481         }
482 
setPortNamePattern(QName value)483         public void setPortNamePattern(QName value) {
484             this.portNamePattern = value;
485             constraintSet = true;
486         }
487 
getPortNamePattern()488         public QName getPortNamePattern() {
489             return portNamePattern;
490         }
491 
getProtocolBindings()492         public List<java.lang.String> getProtocolBindings() {
493             return this.protocolBindings;
494         }
495 
addProtocolBinding(String tokenOrURI)496         public void addProtocolBinding(String tokenOrURI){
497             /*
498             Convert short-form tokens to API's binding ids
499             Unknown token, Put it as it is
500             */
501             tokenOrURI = DeploymentDescriptorParser.getBindingIdForToken(tokenOrURI);
502             String binding = BindingID.parse(tokenOrURI).toString();
503             protocolBindings.add(binding);
504             constraintSet = true;
505         }
506 
isConstraintSet()507         public boolean isConstraintSet() {
508             return constraintSet || !protocolBindings.isEmpty();
509         }
getId()510         public java.lang.String getId() {
511             return id;
512         }
513 
setId(java.lang.String value)514         public void setId(java.lang.String value) {
515             this.id = value;
516         }
517 
getHandlers()518         public List<HandlerType> getHandlers() {
519             if (handlers == null) {
520                 handlers = new ArrayList<HandlerType>();
521             }
522             return this.handlers;
523         }
524     }
525 
526     static class HandlerType {
527         String handlerName;
528         String handlerClass;
529         List<String> soapRoles;
530 
531         java.lang.String id;
532 
533         /** Creates a new instance of HandlerComponent */
HandlerType()534         public HandlerType() {
535         }
536 
getHandlerName()537         public String getHandlerName() {
538             return handlerName;
539         }
540 
setHandlerName(String value)541         public void setHandlerName(String value) {
542             this.handlerName = value;
543         }
544 
getHandlerClass()545         public String getHandlerClass() {
546             return handlerClass;
547         }
548 
setHandlerClass(String value)549         public void setHandlerClass(String value) {
550             this.handlerClass = value;
551         }
552 
getId()553         public java.lang.String getId() {
554             return id;
555         }
556 
setId(java.lang.String value)557         public void setId(java.lang.String value) {
558             this.id = value;
559         }
560 
getSoapRoles()561         public List<String> getSoapRoles() {
562             if (soapRoles == null) {
563                 soapRoles = new ArrayList<String>();
564             }
565             return this.soapRoles;
566         }
567     }
568 }
569