/*******************************************************************************
* 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 org.ws4d.java.communication.TimeoutException;
import org.ws4d.java.schema.ComplexType;
import org.ws4d.java.schema.Element;
import org.ws4d.java.schema.SimpleType;
import org.ws4d.java.service.parameter.ParameterValue;
import org.ws4d.java.types.QName;
import org.ws4d.java.wsdl.WSDLOperation;
/**
* An operation is an abstraction of executable code. Operations are (together
* with {@link DefaultEventSource events}) the main parts of a DPWS service
* implementation.
* <p>
* The actual business logic behind an operation is contained within the
* {@link #invoke(ParameterValue)} method. <code>Operation</code> subclasses are
* required to overwrite it providing the code to be executed when this
* operation is called.
* </p>
* <p>
* Before adding an operation to a {@link DefaultService service}, the types of
* its {@link #getInput() input} and {@link #getOutput() output} parameters must
* be defined in terms of XML Schema constructs like {@link Element element}s,
* {@link SimpleType simple type}s and {@link ComplexType complex types}s. A
* simple operation with no input and a single string message as its only output
* parameter could look like:
*
* <pre>
* Operation myOperation = new Operation() {
*
* public ParameterValue invoke(ParameterValue params)
* throws InvocationException, TimeotException {
* // business logic goes here
* ...
* }
*
* };
* Element message = new Element("message",
* "http://www.example.org/messageService", SchemaUtil.TYPE_STRING);
* myOperation.setOutput(message);
* </pre>
*
* Additionally, if an operation's invocation can cause expected (checked)
* exceptional conditions (errors), they must be declared as
* {@link #addFault(Fault) faults}.
* </p>
* <strong>Note:</strong> According to <a href="http://www.w3.org/TR/wsdl">WSDL
* 1.1 Specification</a>, an operation's {@link #getName() name} is not required
* to be unique within the scope of its containing port type in order to support
* overloading. However, when overloading operations, the combination of each
* one's {@link #getName() name}, {@link #getInputName() input name} and
* {@link #getOutputName() output name} must be unique in order to avoid name
* clashes. </p>
*/
public abstract class Operation extends OperationCommons {
/**
* Creates a new operation instance with the given local <code>name</code>
* and <code>portType</code>.
*
* @param name the name of the operation; see {@link OperationCommons here}
* for a short description of uniqueness requirements regarding
* operation names
* @param portType the qualified port type of the operation
*/
public Operation(String name, QName portType) {
super(name, portType);
}
/**
* Creates a new operation instance without specified name.
*/
public Operation() {
super(null, null);
}
/**
* Creates a new operation instance with the given <code>name</code>.
*
* @param name
*/
public Operation(String name) {
super(name, null);
}
/**
* Creates a new operation instance with the given <code>name</code> and the
* name of the specified service. Namespace default is "http://www.ws4d.or"
* can be set once in the DefaultDevice (setDefaultNamespace). There is also
* the possibility to set the namespace for every operation.
*
* @param name
*/
public Operation(String name, String serviceName) {
super(name, new QName(serviceName, null));
}
protected Operation(WSDLOperation operation) {
super(operation);
}
/**
* Returns the <code>transmission type</code> of this operation according to
* <a href="http://www.w3.org/TR/wsdl">WSDL 1.1 specification</a>. The value
* returned is one of {@link WSDLOperation#TYPE_ONE_WAY} or
* {@link WSDLOperation#TYPE_REQUEST_RESPONSE}.
*
* @return type the transmission type of this operation
*/
public final int getType() {
if (type == WSDLOperation.TYPE_UNKNOWN) {
/*
* this code handles only one-way and request-response operations,
* i.e. operations initiated from the client-side
*/
if (getOutput() == null && getFaultCount() == 0) {
type = WSDLOperation.TYPE_ONE_WAY;
} else {
type = WSDLOperation.TYPE_REQUEST_RESPONSE;
}
}
return type;
}
/**
* Returns <code>true</code> if the transmission type of this operation is
* {@link WSDLOperation#TYPE_ONE_WAY}. Returns <code>false</code> in any
* other case.
*
* @return checks whether this is a {@link WSDLOperation#TYPE_ONE_WAY
* one-way} operation
*/
public final boolean isOneWay() {
return getType() == WSDLOperation.TYPE_ONE_WAY;
}
/**
* Returns <code>true</code> if the transmission type of this operation is
* {@link WSDLOperation#TYPE_REQUEST_RESPONSE}. Returns <code>false</code>
* in any other case.
*
* @return checks whether this is a
* {@link WSDLOperation#TYPE_REQUEST_RESPONSE request-response}
* operation
*/
public final boolean isRequestResponse() {
return getType() == WSDLOperation.TYPE_REQUEST_RESPONSE;
}
/**
* Invokes the operation.
* <p>
* The "business" logic of this operation. This method MUST be implemented
* by the children classes. This method is the center of the universe!
* </p>
* <p>
* When implementing this method, an easy way to create a suitable container
* for the return value for operations with output parameters is provided by
* method {@link #createOutputValue()}. Similarly, clients invoking this
* operation can create the input parameters to pass to it by means of
* {@link #createInputValue()}. If this operation declares any
* {@link #getFaults() faults} which may occur during invocation, these are
* indicated by throwing an appropriate {@link InvocationException} and
* including information about the fault within it. In case a particular
* fault needs user-defined parameters to be provided, creating a value
* container can be accomplished by {@link #createFaultValue(String)} (given
* the fault's name).
* </p>
* <p>
* An example implementation of a simple
* {@link WSDLOperation#TYPE_REQUEST_RESPONSE request-response} operation
* could look like:
*
* <pre>
* public ParameterValue invoke(ParameterValue params)
* throws InvocationException, TimeoutException {
* ... // extract argument values from params and call business logic
* ParameterValue result = createOutputValue(); // create result container
*
* ... // fill-in return value(s) within result
* return result;
* }
* </pre>
*
* </p>
* <p>
* And here is an example of how to indicate that a faulty condition was
* discovered during execution by means of a declared fault:
*
* <pre>
* public ParameterValue invoke(ParameterValue params)
* throws InvocationException, TimeoutException {
* try {
* ... // extract argument values from params and call business logic
* } catch(Exception e) {
* String faultName = ...; // determine type of fault that occurred
* Fault fault = getFault(faultName); // obtain corresponding fault instance
*
* // create container for additional fault information
* ParameterValue additionalFaultDetails = fault.createValue();
* ... // fill-in value(s) within additionalFaultDetails
*
* // create exception and wrap fault and detail data within it
* throw new InvocationException(fault, additionalFaultDetails);
* }
* }
* </pre>
*
* </p>
*
* @param parameterValue a container providing the input parameters of the
* operation
* @return the result of this operation in terms of output parameter value
* which should be delivered to the caller; in case this is just a
* one-way operation, this method must return <code>null</code>;
* returning an empty {@link ParameterValue} still means, that an
* empty response to the caller should be created
* @throws InvocationException thrown to indicate that a declared
* {@link #getFaults() fault} occurred during execution of this
* operation's business logic; clients can extract further
* fault-related information from this exception, such as
* user-defined data attached to it
* @throws TimeoutException in case invoking an operation of a remote
* service times out
*/
public abstract ParameterValue invoke(ParameterValue parameterValue) throws InvocationException, TimeoutException;
}