001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.scxml2.invoke; 018 019import java.io.IOException; 020import java.io.Serializable; 021import java.net.URL; 022import java.util.Map; 023 024import javax.xml.stream.XMLStreamException; 025 026import org.apache.commons.scxml2.Context; 027import org.apache.commons.scxml2.SCXMLExecutor; 028import org.apache.commons.scxml2.SCXMLIOProcessor; 029import org.apache.commons.scxml2.TriggerEvent; 030import org.apache.commons.scxml2.env.SimpleSCXMLListener; 031import org.apache.commons.scxml2.io.SCXMLReader; 032import org.apache.commons.scxml2.model.ModelException; 033import org.apache.commons.scxml2.model.SCXML; 034 035/** 036 * A simple {@link Invoker} for SCXML documents. Invoked SCXML document 037 * may not contain external namespace elements, further invokes etc. 038 */ 039public class SimpleSCXMLInvoker implements Invoker, Serializable { 040 041 /** Serial version UID. */ 042 private static final long serialVersionUID = 1L; 043 /** Parent state ID. */ 044 private String parentStateId; 045 /** Invoking parent SCXMLExecutor */ 046 private SCXMLExecutor parentSCXMLExecutor; 047 /** The invoked state machine executor. */ 048 private SCXMLExecutor executor; 049 /** Cancellation status. */ 050 private boolean cancelled; 051 052 053 /** 054 * {@inheritDoc}. 055 */ 056 @Override 057 public String getInvokeId() { 058 return parentStateId; 059 } 060 061 /** 062 * {@inheritDoc}. 063 */ 064 @Override 065 public void setInvokeId(final String invokeId) { 066 this.parentStateId = invokeId; 067 this.cancelled = false; 068 } 069 070 /** 071 * {@inheritDoc}. 072 */ 073 @Override 074 public void setParentSCXMLExecutor(SCXMLExecutor parentSCXMLExecutor) { 075 this.parentSCXMLExecutor = parentSCXMLExecutor; 076 } 077 078 /** 079 * {@inheritDoc}. 080 */ 081 @Override 082 public SCXMLIOProcessor getChildIOProcessor() { 083 // not used 084 return executor; 085 } 086 087 /** 088 * {@inheritDoc}. 089 */ 090 @Override 091 public void invoke(final String source, final Map<String, Object> params) 092 throws InvokerException { 093 SCXML scxml; 094 try { 095 scxml = SCXMLReader.read(new URL(source)); 096 } catch (ModelException me) { 097 throw new InvokerException(me.getMessage(), me.getCause()); 098 } catch (IOException ioe) { 099 throw new InvokerException(ioe.getMessage(), ioe.getCause()); 100 } catch (XMLStreamException xse) { 101 throw new InvokerException(xse.getMessage(), xse.getCause()); 102 } 103 executor = new SCXMLExecutor(parentSCXMLExecutor); 104 try { 105 executor.setStateMachine(scxml); 106 } 107 catch (ModelException me) { 108 throw new InvokerException(me); 109 } 110 Context rootCtx = executor.getRootContext(); 111 for (Map.Entry<String, Object> entry : params.entrySet()) { 112 rootCtx.setLocal(entry.getKey(), entry.getValue()); 113 } 114 executor.addListener(scxml, new SimpleSCXMLListener()); 115 try { 116 executor.go(); 117 } catch (ModelException me) { 118 throw new InvokerException(me.getMessage(), me.getCause()); 119 } 120 if (executor.getStatus().isFinal()) { 121 TriggerEvent te = new TriggerEvent("done.invoke."+parentStateId, TriggerEvent.SIGNAL_EVENT); 122 new AsyncTrigger(parentSCXMLExecutor, te).start(); 123 } 124 } 125 126 /** 127 * {@inheritDoc}. 128 */ 129 @Override 130 public void parentEvent(final TriggerEvent evt) 131 throws InvokerException { 132 if (cancelled) { 133 return; // no further processing should take place 134 } 135 boolean doneBefore = executor.getStatus().isFinal(); 136 executor.addEvent(evt); 137 if (!doneBefore && executor.getStatus().isFinal()) { 138 TriggerEvent te = new TriggerEvent("done.invoke."+parentStateId,TriggerEvent.SIGNAL_EVENT); 139 new AsyncTrigger(parentSCXMLExecutor, te).start(); 140 } 141 } 142 143 /** 144 * {@inheritDoc}. 145 */ 146 @Override 147 public void cancel() 148 throws InvokerException { 149 cancelled = true; 150 executor.addEvent(new TriggerEvent("cancel.invoke."+parentStateId, TriggerEvent.CANCEL_EVENT)); 151 } 152} 153