001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.description;
021:
022: import org.apache.axiom.om.util.UUIDGenerator;
023: import org.apache.axis2.AxisFault;
024: import org.apache.axis2.client.OperationClient;
025: import org.apache.axis2.client.Options;
026: import org.apache.axis2.context.ConfigurationContext;
027: import org.apache.axis2.context.MessageContext;
028: import org.apache.axis2.context.OperationContext;
029: import org.apache.axis2.context.ServiceContext;
030: import org.apache.axis2.engine.AxisConfiguration;
031: import org.apache.axis2.engine.AxisError;
032: import org.apache.axis2.engine.MessageReceiver;
033: import org.apache.axis2.i18n.Messages;
034: import org.apache.axis2.modules.Module;
035: import org.apache.axis2.phaseresolver.PhaseResolver;
036: import org.apache.axis2.wsdl.WSDLConstants;
037: import org.apache.commons.logging.Log;
038: import org.apache.commons.logging.LogFactory;
039:
040: import javax.xml.namespace.QName;
041: import java.util.ArrayList;
042: import java.util.HashMap;
043: import java.util.Iterator;
044: import java.util.Set;
045:
046: public abstract class AxisOperation extends AxisDescription implements
047: WSDLConstants {
048:
049: public static final String STYLE_RPC = "rpc";
050: public static final String STYLE_MSG = "msg";
051: public static final String STYLE_DOC = "doc";
052:
053: private static final Log log = LogFactory
054: .getLog(AxisOperation.class);
055: /**
056: * message exchange pattern
057: */
058: private int mep = WSDLConstants.MEP_CONSTANT_INVALID;
059:
060: // to hide control operation , operation which added by RM like module
061: private boolean controlOperation = false;
062: private String style = STYLE_DOC;
063:
064: // to store mepURL
065: private String mepURI;
066:
067: private MessageReceiver messageReceiver;
068:
069: private HashMap moduleConfigmap;
070:
071: // To store deploy-time module refs
072: private ArrayList modulerefs;
073:
074: private ArrayList faultMessages;
075:
076: private QName name;
077:
078: private ArrayList wsamappingList;
079: private String outputAction;
080: private HashMap faultActions = new HashMap();
081:
082: private String soapAction;
083:
084: /**
085: * constructor
086: */
087: public AxisOperation() {
088: mepURI = WSDL2Constants.MEP_URI_IN_OUT;
089: modulerefs = new ArrayList();
090: moduleConfigmap = new HashMap();
091: faultMessages = new ArrayList();
092: //setup a temporary name
093: QName tmpName = new QName(this .getClass().getName() + "_"
094: + UUIDGenerator.getUUID());
095: this .setName(tmpName);
096: }
097:
098: public AxisOperation(QName name) {
099: this ();
100: this .setName(name);
101: }
102:
103: public abstract void addMessage(AxisMessage message, String label);
104:
105: /**
106: * Adds a message context into an operation context. Depending on MEPs, this
107: * method has to be overridden.
108: * Depending on the MEP operation description know how to fill the message context map
109: * in operationContext.
110: * As an example, if the MEP is IN-OUT then depending on messagable operation description
111: * should know how to keep them in correct locations.
112: *
113: * @param msgContext <code>MessageContext</code>
114: * @param opContext <code>OperationContext</code>
115: * @throws AxisFault <code>AxisFault</code>
116: */
117: public abstract void addMessageContext(MessageContext msgContext,
118: OperationContext opContext) throws AxisFault;
119:
120: public abstract void addFaultMessageContext(
121: MessageContext msgContext, OperationContext opContext)
122: throws AxisFault;
123:
124: public void addModule(String moduleName) {
125: modulerefs.add(moduleName);
126: }
127:
128: /**
129: * Adds module configuration, if there is moduleConfig tag in operation.
130: *
131: * @param moduleConfiguration
132: */
133: public void addModuleConfig(ModuleConfiguration moduleConfiguration) {
134: moduleConfigmap.put(moduleConfiguration.getModuleName(),
135: moduleConfiguration);
136: }
137:
138: /**
139: * This is called when a module is engaged on this operation. Handle operation-specific
140: * tasks.
141: *
142: * @param axisModule AxisModule
143: * @param engager
144: * @throws AxisFault
145: */
146: public final void onEngage(AxisModule axisModule,
147: AxisDescription engager) throws AxisFault {
148: // Am I the source of this engagement?
149: boolean selfEngaged = (engager == this );
150:
151: // If I'm not, the operations will already have been added by someone above, so don't
152: // do it again.
153: if (selfEngaged) {
154: AxisService service = getAxisService();
155: if (service != null) {
156: service.addModuleOperations(axisModule);
157: }
158: }
159: AxisConfiguration axisConfig = getAxisConfiguration();
160: PhaseResolver phaseResolver = new PhaseResolver(axisConfig);
161: phaseResolver.engageModuleToOperation(this , axisModule);
162: }
163:
164: protected void onDisengage(AxisModule module) {
165: AxisService service = getAxisService();
166: if (service == null)
167: return;
168:
169: AxisConfiguration axisConfiguration = service
170: .getAxisConfiguration();
171: PhaseResolver phaseResolver = new PhaseResolver(
172: axisConfiguration);
173: if (!service.isEngaged(module.getName())
174: && (axisConfiguration != null && !axisConfiguration
175: .isEngaged(module.getName()))) {
176: phaseResolver.disengageModuleFromGlobalChains(module);
177: }
178: phaseResolver.disengageModuleFromOperationChain(module, this );
179:
180: //removing operations added at the time of module engagemnt
181: HashMap moduleOperations = module.getOperations();
182: if (moduleOperations != null) {
183: Iterator moduleOperations_itr = moduleOperations.values()
184: .iterator();
185: while (moduleOperations_itr.hasNext()) {
186: AxisOperation operation = (AxisOperation) moduleOperations_itr
187: .next();
188: service.removeOperation(operation.getName());
189: }
190: }
191: }
192:
193: /**
194: * To remove module from engage module list
195: *
196: * @param module module to remove
197: * @deprecated please use disengageModule(), this method will disappear after 1.3
198: */
199: public void removeFromEngagedModuleList(AxisModule module) {
200: try {
201: disengageModule(module);
202: } catch (AxisFault axisFault) {
203: // Can't do much here...
204: log.error(axisFault.getMessage(), axisFault);
205: }
206: }
207:
208: /**
209: * Gets a copy from module operation.
210: *
211: * @param axisOperation
212: * @return Returns AxisOperation.
213: * @throws AxisFault
214: */
215: private AxisOperation copyOperation(AxisOperation axisOperation)
216: throws AxisFault {
217: AxisOperation operation = AxisOperationFactory
218: .getOperationDescription(axisOperation
219: .getMessageExchangePattern());
220:
221: operation
222: .setMessageReceiver(axisOperation.getMessageReceiver());
223: operation.setName(axisOperation.getName());
224:
225: Iterator parameters = axisOperation.getParameters().iterator();
226:
227: while (parameters.hasNext()) {
228: Parameter parameter = (Parameter) parameters.next();
229:
230: operation.addParameter(parameter);
231: }
232:
233: operation.setWsamappingList(axisOperation.getWSAMappingList());
234: operation.setOutputAction(axisOperation.getOutputAction());
235: String[] faultActionNames = axisOperation.getFaultActionNames();
236: for (int i = 0; i < faultActionNames.length; i++) {
237: operation.addFaultAction(faultActionNames[i], axisOperation
238: .getFaultAction(faultActionNames[i]));
239: }
240: operation.setRemainingPhasesInFlow(axisOperation
241: .getRemainingPhasesInFlow());
242: operation.setPhasesInFaultFlow(axisOperation
243: .getPhasesInFaultFlow());
244: operation.setPhasesOutFaultFlow(axisOperation
245: .getPhasesOutFaultFlow());
246: operation.setPhasesOutFlow(axisOperation.getPhasesOutFlow());
247:
248: return operation;
249: }
250:
251: /**
252: * Returns as existing OperationContext related to this message if one exists.
253: *
254: * @param msgContext
255: * @return Returns OperationContext.
256: * @throws AxisFault
257: */
258: public OperationContext findForExistingOperationContext(
259: MessageContext msgContext) throws AxisFault {
260: OperationContext operationContext;
261:
262: if ((operationContext = msgContext.getOperationContext()) != null) {
263: return operationContext;
264: }
265:
266: // If this message is not related to another one, or it is but not one emitted
267: // from the same operation, don't further look for an operation context or fault.
268: if (null != msgContext.getRelatesTo()) {
269: // So this message may be part of an ongoing MEP
270: ConfigurationContext configContext = msgContext
271: .getConfigurationContext();
272:
273: operationContext = configContext
274: .getOperationContext(msgContext.getRelatesTo()
275: .getValue());
276:
277: if (null == operationContext && log.isDebugEnabled()) {
278: log
279: .debug(msgContext.getLogIDString()
280: + " Cannot correlate inbound message RelatesTo value ["
281: + msgContext.getRelatesTo()
282: + "] to in-progree MEP");
283: }
284: }
285:
286: return operationContext;
287: }
288:
289: /**
290: * Finds a MEPContext for an incoming message. An incoming message can be
291: * of two states.
292: * <p/>
293: * 1)This is a new incoming message of a given MEP. 2)This message is a
294: * part of an MEP which has already begun.
295: * <p/>
296: * The method is special cased for the two MEPs
297: * <p/>
298: * #IN_ONLY #IN_OUT
299: * <p/>
300: * for two reasons. First reason is the wide usage and the second being that
301: * the need for the MEPContext to be saved for further incoming messages.
302: * <p/>
303: * In the event that MEP of this operation is different from the two MEPs
304: * defaulted above the decision of creating a new or this message relates
305: * to a MEP which already in business is decided by looking at the WSA
306: * Relates TO of the incoming message.
307: *
308: * @param msgContext
309: */
310: public OperationContext findOperationContext(
311: MessageContext msgContext, ServiceContext serviceContext)
312: throws AxisFault {
313: OperationContext operationContext;
314:
315: if (null == msgContext.getRelatesTo()) {
316:
317: // Its a new incoming message so get the factory to create a new
318: // one
319: operationContext = serviceContext
320: .createOperationContext(this );
321: } else {
322:
323: // So this message is part of an ongoing MEP
324: ConfigurationContext configContext = msgContext
325: .getConfigurationContext();
326:
327: operationContext = configContext
328: .getOperationContext(msgContext.getRelatesTo()
329: .getValue());
330:
331: if (null == operationContext) {
332: throw new AxisFault(Messages.getMessage(
333: "cannotCorrelateMsg", this .name.toString(),
334: msgContext.getRelatesTo().getValue()));
335: }
336: }
337: return operationContext;
338: }
339:
340: public void registerOperationContext(MessageContext msgContext,
341: OperationContext operationContext) throws AxisFault {
342: msgContext.setAxisOperation(this );
343: msgContext.getConfigurationContext().registerOperationContext(
344: msgContext.getMessageID(), operationContext);
345: operationContext.addMessageContext(msgContext);
346: msgContext.setOperationContext(operationContext);
347: if (operationContext.isComplete()) {
348: operationContext.cleanup();
349: }
350: }
351:
352: public void registerMessageContext(MessageContext msgContext,
353: OperationContext operationContext) throws AxisFault {
354: msgContext.setAxisOperation(this );
355: operationContext.addMessageContext(msgContext);
356: msgContext.setOperationContext(operationContext);
357: if (operationContext.isComplete()) {
358: operationContext.cleanup();
359: }
360: }
361:
362: /**
363: * Maps the String URI of the Message exchange pattern to a integer.
364: * Further, in the first lookup, it will cache the looked
365: * up value so that the subsequent method calls are extremely efficient.
366: */
367: public int getAxisSpecificMEPConstant() {
368: if (this .mep != WSDLConstants.MEP_CONSTANT_INVALID) {
369: return this .mep;
370: }
371:
372: int temp = WSDLConstants.MEP_CONSTANT_INVALID;
373:
374: if (WSDL2Constants.MEP_URI_IN_OUT.equals(mepURI)) {
375: temp = WSDLConstants.MEP_CONSTANT_IN_OUT;
376: } else if (WSDL2Constants.MEP_URI_IN_ONLY.equals(mepURI)) {
377: temp = WSDLConstants.MEP_CONSTANT_IN_ONLY;
378: } else if (WSDL2Constants.MEP_URI_IN_OPTIONAL_OUT
379: .equals(mepURI)) {
380: temp = WSDLConstants.MEP_CONSTANT_IN_OPTIONAL_OUT;
381: } else if (WSDL2Constants.MEP_URI_OUT_IN.equals(mepURI)) {
382: temp = WSDLConstants.MEP_CONSTANT_OUT_IN;
383: } else if (WSDL2Constants.MEP_URI_OUT_ONLY.equals(mepURI)) {
384: temp = WSDLConstants.MEP_CONSTANT_OUT_ONLY;
385: } else if (WSDL2Constants.MEP_URI_OUT_OPTIONAL_IN
386: .equals(mepURI)) {
387: temp = WSDLConstants.MEP_CONSTANT_OUT_OPTIONAL_IN;
388: } else if (WSDL2Constants.MEP_URI_ROBUST_IN_ONLY.equals(mepURI)) {
389: temp = WSDLConstants.MEP_CONSTANT_ROBUST_IN_ONLY;
390: } else if (WSDL2Constants.MEP_URI_ROBUST_OUT_ONLY
391: .equals(mepURI)) {
392: temp = WSDLConstants.MEP_CONSTANT_ROBUST_OUT_ONLY;
393: }
394:
395: if (temp == WSDLConstants.MEP_CONSTANT_INVALID) {
396: throw new AxisError(Messages.getMessage("mepmappingerror"));
397: }
398:
399: this .mep = temp;
400:
401: return this .mep;
402: }
403:
404: /*
405: * (non-Javadoc)
406: *
407: * @see org.apache.axis2.description.AxisService#getEngadgedModules()
408: */
409:
410: public abstract AxisMessage getMessage(String label);
411:
412: public String getMessageExchangePattern() {
413: return mepURI;
414: }
415:
416: public MessageReceiver getMessageReceiver() {
417: return messageReceiver;
418: }
419:
420: public ModuleConfiguration getModuleConfig(String moduleName) {
421: return (ModuleConfiguration) moduleConfigmap.get(moduleName);
422: }
423:
424: public ArrayList getModuleRefs() {
425: return modulerefs;
426: }
427:
428: public QName getName() {
429: return name;
430: }
431:
432: public abstract ArrayList getPhasesInFaultFlow();
433:
434: public abstract ArrayList getPhasesOutFaultFlow();
435:
436: public abstract ArrayList getPhasesOutFlow();
437:
438: public abstract ArrayList getRemainingPhasesInFlow();
439:
440: public String getStyle() {
441: return style;
442: }
443:
444: public ArrayList getWSAMappingList() {
445: return wsamappingList;
446: }
447:
448: public boolean isControlOperation() {
449: return controlOperation;
450: }
451:
452: // to check whether a given parameter is locked
453: public boolean isParameterLocked(String parameterName) {
454:
455: // checking the locked value of parent
456: boolean locked = false;
457:
458: if (getParent() != null) {
459: locked = getParent().isParameterLocked(parameterName);
460: }
461:
462: if (locked) {
463: return true;
464: } else {
465: Parameter parameter = getParameter(parameterName);
466:
467: return (parameter != null) && parameter.isLocked();
468: }
469: }
470:
471: public void setControlOperation(boolean controlOperation) {
472: this .controlOperation = controlOperation;
473: }
474:
475: public void setMessageExchangePattern(String mepURI) {
476: this .mepURI = mepURI;
477: }
478:
479: public void setMessageReceiver(MessageReceiver messageReceiver) {
480: this .messageReceiver = messageReceiver;
481: }
482:
483: public void setName(QName name) {
484: this .name = name;
485: }
486:
487: public abstract void setPhasesInFaultFlow(ArrayList list);
488:
489: public abstract void setPhasesOutFaultFlow(ArrayList list);
490:
491: public abstract void setPhasesOutFlow(ArrayList list);
492:
493: public abstract void setRemainingPhasesInFlow(ArrayList list);
494:
495: public void setStyle(String style) {
496: if (!"".equals(style)) {
497: this .style = style;
498: }
499: }
500:
501: public void setWsamappingList(ArrayList wsamappingList) {
502: this .wsamappingList = wsamappingList;
503: }
504:
505: /**
506: *
507: */
508: public OperationClient createClient(ServiceContext sc,
509: Options options) {
510: throw new UnsupportedOperationException(Messages.getMessage(
511: "mepnotyetimplemented", mepURI));
512: }
513:
514: public Object getKey() {
515: return this .name;
516: }
517:
518: public ArrayList getFaultMessages() {
519: return faultMessages;
520: }
521:
522: public void setFaultMessages(AxisMessage faultMessage) {
523: faultMessages.add(faultMessage);
524: if (getFaultAction(faultMessage.getName()) == null) {
525: addFaultAction(faultMessage.getName(), "urn:"
526: + name.getLocalPart() + faultMessage.getName());
527: }
528: }
529:
530: public void setSoapAction(String soapAction) {
531: this .soapAction = soapAction;
532: }
533:
534: /*
535: * Convenience method to access the WS-A Input Action per the
536: * WS-A spec. Effectively use the soapAction if available else
537: * use the first entry in the WSA Mapping list.
538: *
539: * Use getSoapAction when you want to get the soap action and this
540: * when you want to get the wsa input action.
541: */
542: public String getInputAction() {
543: String result = null;
544: if (soapAction != null && !"".equals(soapAction)) {
545: result = soapAction;
546: } else {
547: if (wsamappingList != null && !wsamappingList.isEmpty()) {
548: result = (String) wsamappingList.get(0);
549: }
550: }
551: return result;
552: }
553:
554: public String getOutputAction() {
555: return outputAction;
556: }
557:
558: public void setOutputAction(String act) {
559: outputAction = act;
560: }
561:
562: public void addFaultAction(String faultName, String action) {
563: faultActions.put(faultName, action);
564: }
565:
566: public void removeFaultAction(String faultName) {
567: faultActions.remove(faultName);
568: }
569:
570: public String getFaultAction(String faultName) {
571: return (String) faultActions.get(faultName);
572: }
573:
574: public String[] getFaultActionNames() {
575: Set keys = faultActions.keySet();
576: String[] faultActionNames = new String[keys.size()];
577: faultActionNames = (String[]) keys.toArray(faultActionNames);
578: return faultActionNames;
579: }
580:
581: public String getFaultAction() {
582: String result = null;
583: Iterator iter = faultActions.values().iterator();
584: if (iter.hasNext()) {
585: result = (String) iter.next();
586: }
587: return result;
588: }
589:
590: /**
591: * All childerns of a AxisOperation must be Messages. So we just return it.
592: * @return
593: */
594:
595: public Iterator getMessages() {
596: return getChildren();
597: }
598:
599: /**
600: * Typesafe access to parent service
601: *
602: * @return the AxisService which contains this AxisOperation
603: */
604: public AxisService getAxisService() {
605: return (AxisService) getParent();
606: }
607:
608: public String getSoapAction() {
609: return soapAction;
610: }
611:
612: }
|