001 /*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements. See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership. The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied. See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 *
020 */
021 package org.apache.qpid.management.wsdm.muse.resources;
022
023 import java.lang.reflect.Method;
024 import java.util.Collection;
025 import java.util.Collections;
026 import java.util.HashMap;
027 import java.util.LinkedHashMap;
028 import java.util.Map;
029 import java.util.Map.Entry;
030
031 import javax.xml.namespace.QName;
032
033 import org.apache.muse.core.Capability;
034 import org.apache.muse.core.Environment;
035 import org.apache.muse.core.ResourceManager;
036 import org.apache.muse.core.routing.MessageHandler;
037 import org.apache.muse.util.xml.XmlUtils;
038 import org.apache.muse.ws.addressing.EndpointReference;
039 import org.apache.muse.ws.addressing.WsaConstants;
040 import org.apache.muse.ws.addressing.soap.SoapConstants;
041 import org.apache.muse.ws.addressing.soap.SoapFault;
042 import org.apache.muse.ws.addressing.soap.SoapUtils;
043 import org.apache.muse.ws.resource.WsResource;
044 import org.apache.muse.ws.resource.metadata.MetadataDescriptor;
045 import org.apache.muse.ws.resource.metadata.WsrmdConstants;
046 import org.apache.muse.ws.resource.metadata.impl.SimpleMetadataDescriptor;
047 import org.apache.muse.ws.resource.metadata.impl.WsrmdUtils;
048 import org.apache.muse.ws.resource.properties.ResourcePropertyCollection;
049 import org.apache.muse.ws.resource.properties.impl.SimpleResourcePropertyCollection;
050 import org.apache.muse.ws.resource.properties.impl.WsrpUtils;
051 import org.apache.muse.ws.resource.properties.schema.ResourcePropertiesSchema;
052 import org.apache.muse.ws.resource.properties.schema.impl.SimpleResourcePropertiesSchema;
053 import org.apache.muse.ws.wsdl.WsdlUtils;
054 import org.apache.qpid.management.Messages;
055 import org.apache.qpid.management.wsdm.common.ThreadSessionManager;
056 import org.apache.qpid.transport.util.Logger;
057 import org.w3c.dom.Document;
058 import org.w3c.dom.Element;
059
060 /**
061 * QMan WS resource.
062 * We could say that this is a QMan manageable entity under the
063 * WS-DM perspective.
064 *
065 * @author Andrea Gazzarini
066 */
067 @SuppressWarnings("unchecked")
068 public class QManWsResource implements WsResource
069 {
070 private final static Logger LOGGER = Logger.get(QManWsResource.class);
071
072 /**
073 * Internal state of this resource.
074 *
075 * @author Andrea Gazzarini
076 */
077 interface State
078 {
079 /**
080 * Provides initialization of this resource.
081 *
082 * @throws SoapFault when the initialization fails.
083 */
084 void initialize() throws SoapFault;
085
086 /**
087 * Returns true if this resource has been initialized.
088 *
089 * @return true if this resource has been initialized.
090 */
091 boolean hasBeenInitialized();
092
093 /**
094 * Returns true if this resource has been shutdown.
095 *
096 * @return true if this resource has been shutdown.
097 */
098 boolean hasBeenShutdown();
099
100 /**
101 * Shuts down this resource.
102 *
103 * @throws SoapFault when the shutdown procedure fails.
104 */
105 void shutdown() throws SoapFault;
106 }
107
108 private final State _hasBeenShutdown = new State()
109 {
110 /**
111 * Return false because this resource has been shutdown so therefore
112 * initialization occurred.
113 *
114 * @return true;
115 */
116 public boolean hasBeenInitialized()
117 {
118 return true;
119 }
120
121 /**
122 * Returns true because this state indicates that resource has been shutdown.
123 *
124 * @return true.
125 */
126 public boolean hasBeenShutdown()
127 {
128 return true;
129 }
130
131 /**
132 * Since this resource has been shutdown the initialization
133 * cannot be performed again.
134 * As conseguence of that this method throws an exception.
135 *
136 * @throws SoapFault each time this method is called.
137 */
138 public void initialize() throws SoapFault
139 {
140 LOGGER.error(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
141 throw new SoapFault(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
142 }
143
144 public void shutdown() throws SoapFault
145 {
146 LOGGER.error(Messages.QMAN_100033_WS_RESOURCE_ALREADY_SHUTDOWN);
147 throw new SoapFault(Messages.QMAN_100033_WS_RESOURCE_ALREADY_SHUTDOWN);
148 }
149 };
150
151 private final State _hasBeenInitialized = new State()
152 {
153 /**
154 * Returns true because this is the state where a resource is when it
155 * has been initialized.
156 *
157 * @return true.
158 */
159 public boolean hasBeenInitialized()
160 {
161 return true;
162 }
163
164 /**
165 * Returns false because this resource has been initialized but no shutdown request
166 * has been received.
167 *
168 * @return false.
169 */
170 public boolean hasBeenShutdown()
171 {
172 return false;
173 }
174
175 /**
176 * A resource in this state cannot be initialized again so if this method is called an
177 * exception is thrown.
178 *
179 * @throws SoapFault each time this method is called.
180 */
181 public void initialize() throws SoapFault
182 {
183 LOGGER.error(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
184 throw new SoapFault(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
185 }
186
187 /**
188 * Shuts down this resource.
189 *
190 * @throws SoapFault when the shutdown procedure fails.
191 */
192 public void shutdown() throws SoapFault
193 {
194 shutdownCapabilities();
195
196 ResourceManager manager = getResourceManager();
197
198 if (manager.getResource(_enpointReference) != null)
199 {
200 manager.removeResource(_enpointReference);
201 }
202
203 _currentState = _hasBeenShutdown;
204 }
205 };
206
207 /**
208 * The initial state of this resource.
209 * As the name suggests, it is not yet initialized.
210 */
211 private final State _notYetInitialized = new State()
212 {
213 /**
214 * Provides initialization of this resource.
215 *
216 * @throws SoapFault when the initialization fails.
217 */
218 public void initialize() throws SoapFault
219 {
220 _properties = new SimpleResourcePropertyCollection();
221 _wsdl = ThreadSessionManager.getInstance().getSession().getWsdlDocument();
222
223 ResourcePropertiesSchema schema = createPropertiesSchema(_wsdl);
224 _properties.setSchema(schema);
225
226 MetadataDescriptor metadata = createMetadataDescriptor(_wsdl);
227 _properties.setMetadata(metadata);
228
229 initializeCapabilities();
230
231 _properties.applyMetadata();
232
233 // Resource intialization completed : Let's make a state change.
234 _currentState = _hasBeenInitialized;
235 }
236
237 /**
238 * Shuts down this resource.
239 *
240 * @throws SoapFault when the shutdown procedure fails. */
241 public void shutdown() throws SoapFault
242 {
243 LOGGER.error(Messages.QMAN_100032_WS_RESOURCE_NOT_YET_INITIALIZED);
244 throw new SoapFault(Messages.QMAN_100032_WS_RESOURCE_NOT_YET_INITIALIZED);
245 }
246
247 /**
248 * Returns false because this state indicates that
249 * the resource has not yet been initialized.
250 *
251 * @return false;
252 */
253 public boolean hasBeenInitialized()
254 {
255 return false;
256 }
257
258 /**
259 * Returns false because the resource, when is in this state
260 * hasn't been initialized and as conseguence of that hasn't
261 * been shutdonm.
262 *
263 * @return false;
264 */
265 public boolean hasBeenShutdown()
266 {
267 return false;
268 }
269 };
270
271 private Map<String,Capability> _capabilitiesByAction = new HashMap<String, Capability>();
272 private Map<String, Capability> _capabilitiesByURI = new LinkedHashMap<String, Capability>();
273
274 private String _contextPath;
275 private Environment _environment;
276 private EndpointReference _enpointReference;
277
278 private State _currentState = _notYetInitialized;
279
280 private ResourceManager _resourceManager;
281 private ResourcePropertyCollection _properties;
282
283 private Map<String,String> _initParameters = Collections.EMPTY_MAP;
284
285 // Workaround : muse is using and hardcoded java.util.logging.Logger but we should use
286 // SLF4j so this is the original implementatation that won't never be used (on QMan classes)
287 private java.util.logging.Logger _logger;
288
289 private Document _wsdl;
290 private String _wsdlPath;
291 private QName _wsdlPortType;
292
293 /**
294 * Adds the given capability to this resource.
295 *
296 * @param capability the capability to be added.
297 */
298 public void addCapability(Capability capability)
299 {
300 capability.setResource(this);
301 capability.setLog(getLog());
302 capability.setEnvironment(getEnvironment());
303
304 String uri = capability.getCapabilityURI();
305 _capabilitiesByURI.put(uri, capability);
306
307 LOGGER.debug(
308 Messages.QMAN_200033_CAPABILITY_CLASS_HAS_BEEN_ADDED,
309 capability.getClass(),
310 uri);
311 }
312
313 /**
314 * Returns the capability associated with the given URI.
315 *
316 * @return the capability associated with the given URI.
317 */
318 public Capability getCapability(String capabilityURI)
319 {
320 return _capabilitiesByURI.get(capabilityURI);
321 }
322
323 /**
324 * Returns a collection with all registered capability URIs.
325 *
326 * @return a collection with all registered capability URIs.
327 */
328 public final Collection getCapabilityURIs()
329 {
330 return Collections.unmodifiableSet(_capabilitiesByURI.keySet());
331 }
332
333 /**
334 * Returns the context path of this resource.
335 *
336 * @return the context path of this resource.
337 */
338 public final String getContextPath()
339 {
340 return _contextPath;
341 }
342
343 /**
344 * Returns the endpoint reference of this resource.
345 *
346 * @return the endpoint reference of this resource.
347 */
348 public EndpointReference getEndpointReference()
349 {
350 return _enpointReference;
351 }
352
353 /**
354 * Returns the enviroment associated with this resource.
355 *
356 * @return the enviroment associated with this resource.
357 */
358 public final Environment getEnvironment()
359 {
360 return _environment;
361 }
362
363 /**
364 * Returns the initialization parameter of this resource associated with
365 * the given name.
366 *
367 * @param name the init parameter name.
368 * @return the initialization parameter associated with the given name.
369 */
370 public final String getInitializationParameter(String name)
371 {
372 return (String)getInitializationParameters().get(name);
373 }
374
375 /**
376 * Returns the map containing all init parameters of this resource.
377 *
378 * @return the map containing all init parameters of this resource.
379 */
380 public final Map<String,String> getInitializationParameters()
381 {
382 return _initParameters;
383 }
384
385 /**
386 * N.A. This resource uses QMan logging instead of plain java.util.logger
387 * implementation.
388 */
389 public final java.util.logging.Logger getLog()
390 {
391 return _logger;
392 }
393
394 /**
395 * Returns the resource manager associated with this resource.
396 *
397 * @return the resource manager associated with this resource.
398 */
399 public ResourceManager getResourceManager()
400 {
401 return _resourceManager;
402 }
403
404 /**
405 * Returns the wsdl (relative) path of this resource.
406 *
407 * @return the wsdl (relative) path of this resource.
408 */
409 public String getWsdlPath()
410 {
411 return _wsdlPath;
412 }
413
414 /**
415 * Returns the port type of this resource.
416 *
417 * @return the port type of this resource.
418 */
419 public final QName getWsdlPortType()
420 {
421 return _wsdlPortType;
422 }
423
424 /**
425 * Returns true if this resource has been initialized, false otherwise.
426 *
427 * @return true if this resource has been initialized, false otherwise.
428 */
429 public final boolean hasBeenInitialized()
430 {
431 return _currentState.hasBeenInitialized();
432 }
433
434 /**
435 * Returns true if this resource has been shutdown, false otherwise.
436 *
437 * @return true if this resource has been shutdown, false otherwise.
438 */
439 public final boolean hasBeenShutdown()
440 {
441 return _currentState.hasBeenShutdown();
442 }
443
444 /**
445 * Checks if a capability with the given URI is available for this resource.
446 *
447 * @return true if a capability with the given URI is available for this resource, false otherwise.
448 */
449 public final boolean hasCapability(String capabilityURI)
450 {
451 return getCapability(capabilityURI) != null;
452 }
453
454 /**
455 * Returns the collection containing all properties of this resource.
456 *
457 * @return the collection containing all properties of this resource.
458 */
459 public final ResourcePropertyCollection getPropertyCollection()
460 {
461 return _properties;
462 }
463
464 /**
465 * Return the WSDL document of this resource.
466 *
467 * @return the WSDL document of this resource.
468 */
469 public Document getWsdl()
470 {
471 return _wsdl;
472 }
473
474 /**
475 * Initializes this resources.
476 * Note that the what needs to be done depends on the current state of this
477 * resource.
478 *
479 * @throws SoapFault when the initialization fails.
480 */
481 public void initialize() throws SoapFault
482 {
483 _currentState.initialize();
484 }
485
486 /**
487 * Invokes the action specified in the given soap request on this resource.
488 *
489 * @param requestBody the SOAP body.
490 * @return the result of the invocation as org.w3c.dom.Element
491 */
492 public Element invoke(Element requestBody)
493 {
494 String action = _environment.getAddressingContext().getAction();
495 Capability capability = getCapabilityForAction(action);
496
497 // Sanity check : is there a capability for the given action?
498 if (capability == null)
499 {
500 SoapFault wsaFault = new SoapFault(
501 String.format(
502 Messages.ACTION_NOT_SUPPORTED,
503 action,getContextPath()));
504
505 wsaFault.setCode(SoapConstants.SENDER_QNAME);
506 wsaFault.setSubCode(WsaConstants.ACTION_NOT_SUPPORTED_FAULT_QNAME);
507
508 Element detail = XmlUtils.createElement(WsaConstants.PROBLEM_ACTION_QNAME);
509 XmlUtils.setElement(detail, WsaConstants.ACTION_QNAME, action);
510 wsaFault.setDetail(detail);
511
512 LOGGER.error(
513 Messages.QMAN_100020_ACTION_NOT_SUPPORTED,
514 action,
515 getContextPath());
516
517 return wsaFault.toXML();
518 }
519
520 MessageHandler handler = capability.getMessageHandler(action);
521 Method method = handler.getMethod();
522
523 try
524 {
525 Object[]parameters = handler.fromXML(requestBody);
526 Object result = method.invoke(capability, parameters);
527 return handler.toXML(result);
528 }
529 catch (Throwable throwable)
530 {
531 LOGGER.error(
532 throwable,
533 Messages.QMAN_100037_INVOKE_OPERATION_FAILURE);
534
535 SoapFault response = SoapUtils.convertToFault(
536 (throwable.getCause()!= null)
537 ? throwable.getCause()
538 : throwable);
539 return response.toXML();
540 }
541 }
542
543 /**
544 * Sets the context path of this resource.
545 *
546 * @param contextPath the context path of this resource.
547 */
548 public final void setContextPath(String contextPath)
549 {
550 _contextPath = contextPath;
551 }
552
553 /**
554 * Sets the endpoint reference of this resource.
555 *
556 * @param endpointReference the endpoint reference of this resource.
557 */
558 public final void setEndpointReference(EndpointReference endpointReference)
559 {
560 if (_enpointReference != null && hasBeenInitialized())
561 throw new RuntimeException(("ExistingResourceEPR"));
562
563 _enpointReference = endpointReference;
564 }
565
566 /**
567 * Sets the context environment of this resource.
568 *
569 * @param environment the context environment of this resource.
570 */
571 public final void setEnvironment(Environment environment)
572 {
573 _environment = environment;
574 }
575
576 /**
577 * Sets the initialization parameters of this resource.
578 *
579 * @param parameters the init parameters of this resource.
580 */
581 public final void setInitializationParameters(Map parameters)
582 {
583 _initParameters = (parameters != null)
584 ? parameters
585 : Collections.EMPTY_MAP;
586 }
587
588 /**
589 * N.A. for this resource. QMan logging mechanism is used for that.
590 */
591 public final void setLog(java.util.logging.Logger log)
592 {
593 _logger = log;
594 }
595
596 /**
597 * Sets the resource manager owner of this resource.
598 *
599 * @param manager the resource manager of this resource.
600 */
601 public void setResourceManager(ResourceManager manager)
602 {
603 _resourceManager = manager;
604 }
605
606 /**
607 * Sets the WSDL (relative) path of this resource.
608 *
609 * @param wsdlPath the WSDL (relative) path of this resource.
610 */
611 public final void setWsdlPath(String wsdlPath)
612 {
613 this._wsdlPath = wsdlPath;
614 }
615
616 /**
617 * Sets the port type of this resource.
618 *
619 * @param wsdlPortType the port type of this resource.
620 */
621 public final void setWsdlPortType(QName wsdlPortType)
622 {
623 _wsdlPortType = wsdlPortType;
624 }
625
626 /**
627 * Shutdown procedure for this resource.
628 *
629 * @throws SoapFault when the shutdown procedure fails.
630 */
631 public synchronized void shutdown() throws SoapFault
632 {
633 _currentState.shutdown();
634 }
635
636 /**
637 * Returns a string representation of this resource.
638 * Basically the resource endpoint reference (as a string) is returned.
639 *
640 * @return the resource endpoint reference (as a string) is returned.
641 */
642 public String toString()
643 {
644 return getEndpointReference().toString();
645 }
646
647 /**
648 * Initializes capabilities of this resource.
649 *
650 * @throws SoapFault when at least one capability fails to initialize.
651 */
652 private void initializeCapabilities() throws SoapFault
653 {
654 for (Entry<String, Capability> entry : _capabilitiesByURI.entrySet())
655 {
656 Capability capability = entry.getValue();
657 capability.initialize();
658
659 for (Object action : capability.getActions())
660 {
661 _capabilitiesByAction.put((String)action, capability);
662 }
663
664 capability.initializeCompleted();
665 }
666 }
667
668 /**
669 * Shutdown procedure for all registered capabilities of this resource.
670 *
671 * @throws SoapFault when at least one capability shutdown fails.
672 */
673 private void shutdownCapabilities() throws SoapFault
674 {
675 for (Entry<String,Capability> entry : _capabilitiesByURI.entrySet())
676 {
677 Capability capabilty = entry.getValue();
678 capabilty.prepareShutdown();
679 capabilty.shutdown();
680 }
681 }
682
683 /**
684 * Creates a metadata descriptor for this resource.
685 *
686 * @param wsdl the WSDL document.
687 * @return a metadata descriptor for this resource.
688 * @throws SoapFault when it's not possible build the descriptor.
689 */
690 private MetadataDescriptor createMetadataDescriptor(Document wsdl) throws SoapFault
691 {
692 try
693 {
694 Element portTypeXML = WsdlUtils.getPortType(wsdl, getWsdlPortType());
695
696 String rmdName = XmlUtils.getAttribute(
697 portTypeXML,
698 WsrmdConstants.DESCRIPTOR_ATTR_QNAME);
699
700 String rmdPath = XmlUtils.getAttribute(
701 portTypeXML,
702 WsrmdConstants.DESCRIPTOR_LOCATION_ATTR_QNAME);
703
704 LOGGER.debug(Messages.QMAN_200034_RMD_NAME, rmdName);
705 LOGGER.debug(Messages.QMAN_200035_RMD_PATH, rmdPath);
706
707 Environment env = getEnvironment();
708 String path = env.createRelativePath(getWsdlPath(), rmdPath);
709 Document rmdDoc = env.getDocument(path);
710
711 Element[] additionalProperties =
712 ThreadSessionManager
713 .getInstance()
714 .getSession()
715 .getResourceMetadataDescriptor();
716
717 Element metadataDescriptor = WsrmdUtils.getMetadataDescriptor(rmdDoc, rmdName);
718
719 for (Element element : additionalProperties)
720 {
721
722 // rmdDoc.importNode(element, true);
723 Element adopted = (Element) rmdDoc.importNode(element,false);
724 metadataDescriptor.appendChild(adopted);
725 }
726
727 return new SimpleMetadataDescriptor(metadataDescriptor);
728 }
729 catch(Exception exception)
730 {
731 LOGGER.error(
732 exception,
733 Messages.QMAN_100021_RMD_BUID_FAILURE,
734 getContextPath());
735 throw new SoapFault(exception);
736 }
737 }
738
739 /**
740 * Returns the capability associated with the given action.
741 *
742 * @param action the wsa:action of the requested capability.
743 * @return the capability associated with the given action.
744 */
745 private Capability getCapabilityForAction(String action)
746 {
747 return (Capability)_capabilitiesByAction.get(action);
748 }
749
750 /**
751 * Creates a WSRP document representing schema properties for this resource.
752 *
753 * @param wsdl the DOM document holding the resource's WSDL.
754 * @return the WSRP document schema.
755 */
756 private ResourcePropertiesSchema createPropertiesSchema(Document wsdl)
757 {
758 QName wsrpName = WsrpUtils.getPropertiesName(wsdl, getWsdlPortType());
759 Element wsrpDoc = WsdlUtils.getElementDeclaration(wsdl, wsrpName);
760 return new SimpleResourcePropertiesSchema(wsrpName, wsrpDoc);
761 }
762 }
|