/******************************************************************************* * Copyright (c) 2009 MATERNA Information & Communications. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html. For further * project-related information visit http://www.ws4d.org. The most recent * version of the JMEDS framework can be obtained from * http://sourceforge.net/projects/ws4d-javame. ******************************************************************************/ package org.ws4d.java.service; import java.io.IOException; import org.ws4d.java.DPWSFramework; import org.ws4d.java.eventing.EventSource; import org.ws4d.java.eventing.EventingFactory; import org.ws4d.java.structures.DataStructure; import org.ws4d.java.structures.EmptyStructures; import org.ws4d.java.structures.HashMap; import org.ws4d.java.structures.HashSet; import org.ws4d.java.structures.Iterator; import org.ws4d.java.structures.ReadOnlyIterator; import org.ws4d.java.structures.Set; import org.ws4d.java.types.AttributableSupport; import org.ws4d.java.types.CustomAttributeValue; import org.ws4d.java.types.EprInfo; import org.ws4d.java.types.QName; import org.ws4d.java.util.Log; import org.ws4d.java.wsdl.WSDL; import org.ws4d.java.wsdl.WSDLOperation; import org.ws4d.java.wsdl.WSDLPortType; /** * Class represents the common part of a proxy/local DPWS device. */ public abstract class ServiceCommons implements Service { // key = portType as QName, value = PortType instance final HashMap portTypes = new HashMap(); // key = wsa:Action as String, value = Operation instance final HashMap operations = new HashMap(); // key = wsa:Action as String, value = Event instance final HashMap events = new HashMap(); /* * we store different WSDL documents, one for each target namespace of our * service types */ protected final HashMap wsdls = new HashMap(); /** Security */ protected boolean secure = false; protected Object certificate; protected Object privateKey; ServiceCommons() { super(); } /* * ADDED 2011-01-17 by Stefan Schlichting: added to allow extension * synchronize necessary */ protected HashMap getPortTypesInternal() { return portTypes; } protected HashMap getOperationsInternal() { return operations; } protected HashMap getEventsInternal() { return events; } /* * (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { StringBuffer sb = new StringBuffer(getClass().getName()); sb.append(" [ serviceId=").append(getServiceId()); Iterator it = getEprInfos(); if (it.hasNext()) { sb.append(", endpointReferences={ "); while (it.hasNext()) { sb.append(((EprInfo)it.next()).getEndpointReference()).append(' '); } sb.append('}'); } it = getPortTypes(); if (it.hasNext()) { sb.append(", portTypes={ "); while (it.hasNext()) { sb.append(it.next()).append(' '); } sb.append('}'); } sb.append(" ]"); return sb.toString(); } /* * (non-Javadoc) * @see org.ws4d.java.service.Service#getOperations() */ public Iterator getOperations() { Set operations = new HashSet(); for (Iterator it = portTypes.values().iterator(); it.hasNext();) { PortType type = (PortType) it.next(); for (Iterator it2 = type.getOperations(); it2.hasNext();) { operations.add(it2.next()); } } return new ReadOnlyIterator(operations); } /* * (non-Javadoc) * @see * org.ws4d.java.service.Service#getOperations(org.ws4d.java.types.QName) */ public Iterator getOperations(QName portType) { PortType type = (PortType) portTypes.get(portType); return type == null ? EmptyStructures.EMPTY_ITERATOR : new ReadOnlyIterator(type.getOperations()); } /* * (non-Javadoc) * @see * org.ws4d.java.service.Service#getOperation(org.ws4d.java.types.QName, * java.lang.String, java.lang.String, java.lang.String) */ public Operation getOperation(QName portType, String opName, String inputName, String outputName) { if (opName == null) { return null; } PortType type = (PortType) portTypes.get(portType); return type == null ? null : type.getOperation(opName, inputName, outputName); } /* * (non-Javadoc) * @see org.ws4d.java.service.Service#getOperation(java.lang.String) */ public Operation getOperation(String inputAction) { return (Operation) operations.get(inputAction); } /* * (non-Javadoc) * @see * org.ws4d.java.service.Service#getAnyOperation(org.ws4d.java.types.QName, * java.lang.String) */ public Operation getAnyOperation(QName portType, String operationName) { if (operationName == null) { return null; } for (Iterator it = getOperations(portType); it.hasNext();) { Operation operation = (Operation) it.next(); if (operationName.equals(operation.getName())) { return operation; } } return null; } /* * (non-Javadoc) * @see org.ws4d.java.service.Service#getEventSources() */ public Iterator getEventSources() { Set events = new HashSet(); for (Iterator it = portTypes.values().iterator(); it.hasNext();) { PortType type = (PortType) it.next(); for (Iterator it2 = type.getEventSources(); it2.hasNext();) { events.add(it2.next()); } } return new ReadOnlyIterator(events); } /* * (non-Javadoc) * @see * org.ws4d.java.service.Service#getEventSources(org.ws4d.java.types.QName) */ public Iterator getEventSources(QName portType) { PortType type = (PortType) portTypes.get(portType); return type == null ? EmptyStructures.EMPTY_ITERATOR : new ReadOnlyIterator(type.getEventSources()); } /* * (non-Javadoc) * @see * org.ws4d.java.service.Service#getEventSource(org.ws4d.java.types.QName, * java.lang.String, java.lang.String, java.lang.String) */ public EventSource getEventSource(QName portType, String eventName, String inputName, String outputName) { if (eventName == null) { return null; } PortType type = (PortType) portTypes.get(portType); return type == null ? null : type.getEventSource(eventName, inputName, outputName); } /* * (non-Javadoc) * @see org.ws4d.java.service.Service#getEventSource(java.lang.String) */ public EventSource getEventSource(String outputAction) { return (EventSource) events.get(outputAction); } /* * (non-Javadoc) * @see * org.ws4d.java.service.Service#getAnyEventSource(org.ws4d.java.types.QName * , java.lang.String) */ public EventSource getAnyEventSource(QName portType, String eventName) { if (eventName == null) { return null; } for (Iterator it = getEventSources(portType); it.hasNext();) { EventSource event = (EventSource) it.next(); if (eventName.equals(event.getName())) { return event; } } return null; } /* * (non-Javadoc) * @see * org.ws4d.java.service.Service#getPortTypeAttribute(org.ws4d.java.types * .QName, org.ws4d.java.types.QName) */ public CustomAttributeValue getPortTypeAttribute(QName portTypeName, QName attributeName) { PortType portType = (PortType) portTypes.get(portTypeName); if (portType == null) { throw new IllegalArgumentException("no such port type: " + portTypeName); } return portType.getAttribute(attributeName); } /** * Sets the <code>value</code> of the port type attribute with the specified * <code>name</code> of the port type with the given unique * <code>portTypeName</code>. Throws a * <code>java.lang.IllegalArgumentException</code> in case there is no port * type with the given <code>portTypeName</code> within this service * instance or if <code>name</code> is <code>null</code>. * * @param portTypeName the unique name of the port type within the scope of * this service instance, see {@link #getPortTypes()} * @param attributeName the name of the port type attribute to set, must not * be <code>null</code> * @param value the value to set the named port type attribute to (may be * <code>null</code> * @throws IllegalArgumentException if there is no port type with the given * <code>portTypeName</code> within this service instance or if * <code>name</code> is <code>null</code> */ public void setPortTypeAttribute(QName portTypeName, QName attributeName, CustomAttributeValue value) { PortType portType = (PortType) portTypes.get(portTypeName); if (portType == null) { throw new IllegalArgumentException("no such port type: " + portTypeName); } portType.setAttribute(attributeName, value); } /* * (non-Javadoc) * @see * org.ws4d.java.service.Service#getPortTypeAttributes(org.ws4d.java.types * .QName) */ public HashMap getPortTypeAttributes(QName portTypeName) { PortType portType = (PortType) portTypes.get(portTypeName); if (portType == null) { throw new IllegalArgumentException("no such port type: " + portTypeName); } return portType.getAttributes(); } /** * Sets all port type attributes of the port type with unique * <code>portTypeName</code> at once to those contained within argument * <code>attributes</code>. Note that depending on the actual * implementation, it is possible that the map <code>attributes</code> * points at may be used for the actual internal storage of the port type * attributes (i.e. without copying it). That is why, after passing it to * this method, modifications to this map should be made with care. This * method throws a <code>java.lang.IllegalArgumentException</code> in case * <code>attributes</code> is <code>null</code>. * * @param portTypeName the unique name of the port type within the scope of * this service instance, see {@link #getPortTypes()} * @param attributes the new port type attributes to set * @throws IllegalArgumentException if no port type with the given * <code>portTypeName</code> is found or if * <code>attributes</code> is <code>null</code> */ public void setPortTypeAttributes(QName portTypeName, HashMap attributes) { PortType portType = (PortType) portTypes.get(portTypeName); if (portType == null) { throw new IllegalArgumentException("no such port type: " + portTypeName); } portType.setAttributes(attributes); } /* * (non-Javadoc) * @see * org.ws4d.java.service.Service#hasPortTypeAttributes(org.ws4d.java.types * .QName) */ public boolean hasPortTypeAttributes(QName portTypeName) { PortType portType = (PortType) portTypes.get(portTypeName); return portType != null && portType.hasAttributes(); } /** * Sets the service to use security techniques. Use this method after * setting the services HTTPSBinding * * @throws Exception */ public void setSecureService() throws Exception { if (!DPWSFramework.hasModule(DPWSFramework.SECURITY_MODULE)) { throw new RuntimeException("You are running the DPWS Framework without the required Security-Module"); } this.secure = true; } /** * Sends using WS-Security techniques. */ public boolean isSecure() { return secure; } public void setSecure(boolean sec) { secure = sec; } /** * @param certificate must be the java.security.cert.Certificate of the * sender device/service */ public void setCertificate(Object certificate) { if (certificate == null) return; this.certificate = certificate; this.setSecure(true); } public Object getCertificate() { return certificate; } public Object getPrivateKey() { return privateKey; } /** * @param privKey must be the java.security.PrivateKey of the sender device/ * service */ public void setPrivateKey(Object privKey) { this.privateKey = privKey; } protected void processWSDLPortType(WSDLPortType portType) { QName portTypeName = portType.getName(); if (portTypes.containsKey(portTypeName)) { /* * we have already imported this port type probably through a * different WSDL file */ return; } PortType port = new PortType(); if (portType.hasAttributes()) { port.setAttributes(portType.getAttributes()); } DataStructure operations = portType.getOperations(); for (Iterator it = operations.iterator(); it.hasNext();) { WSDLOperation operation = (WSDLOperation) it.next(); OperationCommons op; if (operation.isRequest()) { Operation realOp = createOperation(operation); op = realOp; port.addOperation(new OperationSignature(op), realOp); this.operations.put(realOp.getInputAction(), realOp); if (Log.isDebug()) { Log.debug("[NEW OPERATION]: " + realOp.toString(), Log.DEBUG_LAYER_APPLICATION); } } else if (operation.isEvented()) { EventSource realEvent = createEventSource(operation); if (realEvent == null || !(realEvent instanceof OperationCommons)) { Log.error("Cannot create event source from " + operation + ". Event does not exist, or is not a extension of operation."); continue; } op = (OperationCommons) realEvent; port.addEventSource(new OperationSignature(op), realEvent); this.events.put(realEvent.getOutputAction(), realEvent); if (Log.isDebug()) { Log.debug("[NEW EVENT SOURCE]: " + realEvent.toString(), Log.DEBUG_LAYER_APPLICATION); } } else { throw new IllegalArgumentException("Unknown type of WSDL operation: " + operation); } /* * no need to check names, as they should be correctly sent by * existing service or within given WSDL; if not, than it is not our * fault :D */ op.setService(this); } portTypes.put(portTypeName, port); } /** * Creates an {@link Operation} instance suitable for usage within this * service instance. This method is only called from within * {@link #processWSDLPortType(WSDLPortType)} and should not be used in * other contexts. * * @param wsdlOperation the WSDL operation describing the operation to * create * @return the operation to add */ protected abstract Operation createOperation(WSDLOperation wsdlOperation); /** * Creates a {@link DefaultEventSource} instance suitable for usage within * this service instance. This method is only called from within * {@link #processWSDLPortType(WSDLPortType)} and should not be used in * other contexts. * * @param wsdlOperation the WSDL operation describing the event source to * create * @return the event source to add */ protected EventSource createEventSource(WSDLOperation wsdlOperation) { if (DPWSFramework.hasModule(DPWSFramework.EVENTING_MODULE)) { try { EventingFactory eFac = DPWSFramework.getEventingFactory(); return eFac.createDefaultEventSource(wsdlOperation); } catch (IOException e) { Log.error("Cannot create event source from " + wsdlOperation + ". " + e.getMessage()); } } else { Log.error("Cannot create event source, event support missing."); } return null; } /* * (non-Javadoc) * @see org.ws4d.java.service.Service#getDescriptions() */ public Iterator getDescriptions() { return new ReadOnlyIterator(wsdls.values().iterator()); } protected WSDL getExistingDescription(String targetNamespace) { if (wsdls.size() > 0) { WSDL wsdl = (WSDL) wsdls.get(targetNamespace); if (wsdl != null) { return wsdl; } // try linked WSDLs for (Iterator it = wsdls.values().iterator(); it.hasNext();) { wsdl = (WSDL) it.next(); WSDL child = wsdl.getLinkedWsdlRecursive(targetNamespace); if (child != null) { return child; } } } return null; } // Changed SSch 2011-01-17 Allow extension from other packages public static class PortType extends AttributableSupport { // key = OperationSignature instance, value = Operation instance protected final HashMap operations = new HashMap(); // key = OperationSignature instance, value = Event instance protected final HashMap events = new HashMap(); protected boolean plombed; public boolean contains(OperationSignature signature) { return operations.containsKey(signature) || events.containsKey(signature); } public boolean hasOperations() { return operations.size() != 0; } public Iterator getOperations() { return operations.values().iterator(); } public Operation getOperation(String name, String inputName, String outputName) { // compatible with overloaded operations (use input/output names) return (Operation) operations.get(new OperationSignature(name, inputName, outputName)); } public void addOperation(OperationSignature signature, Operation operation) { operations.put(signature, operation); } public boolean hasEventSources() { return events.size() != 0; } public Iterator getEventSources() { return events.values().iterator(); } public EventSource getEventSource(String name, String inputName, String outputName) { // compatible with overloaded operations (use input/output names) return (EventSource) events.get(new OperationSignature(name, inputName, outputName)); } public void addEventSource(OperationSignature signature, EventSource event) { events.put(signature, event); } public boolean isPlombed() { return plombed; } protected void plomb() { plombed = true; } } // Changed SSch 2011-01-17 Allow extension from other packages public static class OperationSignature { private final String name; private final String inputName; private final String outputName; public OperationSignature(OperationDescription opDescription) { this(opDescription.getName(), opDescription.getInputName(), opDescription.getOutputName()); } /** * @param name * @param inputName * @param outputName */ public OperationSignature(String name, String inputName, String outputName) { super(); this.name = name; this.inputName = inputName; // == null ? "" : inputName; this.outputName = outputName; // == null ? "" : outputName; } /* * (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } OperationSignature other = (OperationSignature) obj; if (!name.equals(other.name)) { return false; } if (inputName == null) { if (other.inputName != null) { return false; } } else if (!inputName.equals(other.inputName)) { return false; } if (outputName == null) { if (other.outputName != null) { return false; } } else if (!outputName.equals(other.outputName)) { return false; } return true; } /* * (non-Javadoc) * @see java.lang.Object#hashCode() */ public int hashCode() { final int prime = 31; int result = 1; result = prime * result + name.hashCode(); result = prime * result + ((inputName == null) ? 0 : inputName.hashCode()); result = prime * result + ((outputName == null) ? 0 : outputName.hashCode()); return result; } } }