/**
* This file is part of PaxmlCore.
*
* PaxmlCore is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PaxmlCore is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with PaxmlCore. If not, see <http://www.gnu.org/licenses/>.
*/
package org.paxml.launch;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.paxml.core.Context;
import org.paxml.core.EntityFactoryRegistry;
import org.paxml.core.IEntity;
import org.paxml.core.IEntityExecutionListener;
import org.paxml.core.IExecutionListener;
import org.paxml.core.ITagExecutionListener;
import org.paxml.core.Parser;
import org.paxml.core.PaxmlResource;
import org.paxml.core.PaxmlRuntimeException;
import org.paxml.core.ResourceLocator;
import org.paxml.tag.AbstractTag;
import org.paxml.tag.ITagLibrary;
import org.paxml.util.PaxmlUtils;
import org.paxml.util.ReflectUtils;
import org.springframework.core.io.Resource;
/**
* paxml operations starting point.
*
* @author Xuetao Niu
*
*/
public class Paxml {
private static final Log log = LogFactory.getLog(Paxml.class);
private final Parser parser;
private final long processId;
private final long sessionId;
private volatile List<IExecutionListener> paxmlExecutionListeners;
private volatile List<IEntityExecutionListener> entityExecutionListeners;
private volatile List<ITagExecutionListener> tagExecutionListeners;
/**
* Construct from default paxml entity registry.
*
* @param processId
* the processId
*/
public Paxml(long processId, long sessionId) {
this(EntityFactoryRegistry.getDefaultRegistry(), processId, sessionId);
}
/**
* Construct from given paxml entity registry.
*
* @param reg
* the registry
* @param processId
* the processId
*/
public Paxml(final EntityFactoryRegistry reg, long processId, long sessionId) {
parser = new Parser(this, reg, new ResourceLocator());
this.processId = processId;
this.sessionId = sessionId;
}
/**
* Add a static config to this.
*
* @param config
* the config
*/
public void addStaticConfig(StaticConfig config) {
// add resources
getResourceLocator().addResources(config.getResources());
// add tag libs
for (Class<? extends ITagLibrary> lib : config.getTagLibs()) {
addTagLibrary(lib);
}
// add listeners
for (Class<? extends IExecutionListener> lis : config.getExecutionListeners()) {
addPaxmlExecutionListener(ReflectUtils.createObject(lis));
}
for (Class<? extends IEntityExecutionListener> lis : config.getEntityListeners()) {
addEntityExecutionListener(ReflectUtils.createObject(lis));
}
for (Class<? extends ITagExecutionListener> lis : config.getTagListeners()) {
addTagExecutionListener(ReflectUtils.createObject(lis));
}
}
public ResourceLocator getResourceLocator() {
return parser.getResourceLocator();
}
/**
* Execute a paxml resource.
*
* @param name
* the resource name
* @param initialProperties
* the initial properties
* @return the execution result
*/
public Object execute(String name, Properties topLevelProperties, Properties initialProperties) {
IEntity entity = getEntity(name);
if (entity == null) {
throw new PaxmlRuntimeException("Entity with name '" + name + "' unknown!");
}
return execute(entity, topLevelProperties, initialProperties);
}
/**
* Get paxml entity by name, triggering the parse if needed.
*
* @param name
* the tag name
* @return the parsed entity, or null if not found.
*/
public IEntity getEntity(String name) {
return parser.getResourceLocator().getEntity(name, null);
}
/**
* Execute a paxml entity.
*
* @param entity
* the paxml entity
* @param topLevelProperties
* the top level properties.
* @param initialProperties
* the initial properties.
* @return the execution result
*/
public Object execute(IEntity entity, Properties topLevelProperties, Properties initialProperties) {
Context context = new Context(topLevelProperties, processId);
if (initialProperties != null) {
context = new Context(context);
context.addProperties(initialProperties);
}
return execute(entity, context, true, true);
}
/**
* Execute a paxml entity.
*
* @param entity
* the paxml entity
* @param rootContext
* the root context, null to automatically create one.
* @param callEntryListener
* if to call the entity entry listener or not
* @param callExitListener
* if to call the entity exit listener or not
*
*
* @return the execution result
*/
public Object execute(IEntity entity, Context rootContext, boolean callEntryListener, boolean callExitListener) {
final Context propertiesContext = rootContext == null ? new Context(System.getProperties(), processId) : rootContext;
final Context context = new Context(propertiesContext);
context.setAsCurrentThreadContext();
context.setPaxml(this);
context.setPaxmlExecutionListeners(paxmlExecutionListeners);
context.setEntityExecutionListeners(entityExecutionListeners);
context.setTagExecutionListeners(tagExecutionListeners);
if (propertiesContext.isRoot()) {
if (log.isInfoEnabled()) {
log.info("Starting process " + processId + " to execute scenario: " + entity.getResource().getPath());
}
}
try {
if (callEntryListener && paxmlExecutionListeners != null) {
for (IExecutionListener listener : context.getPaxmlExecutionListeners(false)) {
listener.onEntry(this, context);
}
}
Object result = entity.execute(context);
return result;
} catch (Throwable e) {
String msg = getCause(e);
throw new PaxmlRuntimeException((msg == null ? "" : msg), e);
} finally {
if (callExitListener) {
List<Throwable> exceptions = callEntityExitListener(context);
if (exceptions != null && exceptions.size() > 0) {
if (log.isErrorEnabled()) {
log.error(exceptions.size() + " error(s) executing paxml exit listener:");
int i = 1;
for (Throwable t : exceptions) {
log.error("Error number " + (i++), t);
}
}
throw new PaxmlRuntimeException("Exception(s) occurred while calling the onExit() method(s) on paxml execution listener(s). "
+ "See the error log for details.", null);
}
}
}
}
public List<Throwable> callEntityExitListener(Context context) {
List<Throwable> exceptions = null;
paxmlExecutionListeners = context.getPaxmlExecutionListeners(false);
if (paxmlExecutionListeners != null) {
for (IExecutionListener listener : paxmlExecutionListeners) {
try {
listener.onExit(this, context);
} catch (Throwable e) {
if (exceptions == null) {
exceptions = new ArrayList<Throwable>();
}
exceptions.add(e);
if (log.isErrorEnabled()) {
log.error("Exception in the end of paxml execution", e);
}
}
}
}
return exceptions;
}
public static String getCause(Throwable t) {
String msg = null;
while (t != null && StringUtils.isNotBlank((msg = t.getMessage()))) {
t = t.getCause();
}
return msg;
}
/**
* Add tag library.
*
* @param classes
* tag library classes.
* @return this
*/
public Paxml addTagLibrary(Class<? extends ITagLibrary>... classes) {
for (Class<? extends ITagLibrary> clazz : classes) {
ITagLibrary lib = ReflectUtils.createObject(clazz);
// let later libs overwrite earlier ones, the system default lib is
// the earliest one
parser.addTagLibrary(lib, false);
}
return this;
}
/**
* Add paxml resources.
*
* @param resources
* the resources.
* @return this
*/
public Paxml addResources(PaxmlResource... resources) {
for (PaxmlResource resource : resources) {
parser.getResourceLocator().addResource(resource);
}
return this;
}
/**
* Add paxml resources.
*
* @param resources
* the resources
* @return this
*/
public Paxml addResources(Collection<PaxmlResource> resources) {
for (PaxmlResource resource : resources) {
parser.getResourceLocator().addResource(resource);
}
return this;
}
/**
* Remove paxml resources.
*
* @param resources
* the resources
* @return this
*/
public Paxml removeResources(Collection<PaxmlResource> resources) {
for (PaxmlResource resource : resources) {
parser.getResourceLocator().removeResource(resource);
}
return this;
}
/**
* Remove paxml resources.
*
* @param resources
* the resources
* @return this
*/
public Paxml removeResources(PaxmlResource... resources) {
for (PaxmlResource resource : resources) {
parser.getResourceLocator().removeResource(resource);
}
return this;
}
/**
* Inspect a parsed paxml entity.
*
* @param name
* the name of the paxml entity
* @return the printed xml tree in string.
*/
public String inspectEntity(String name) {
AbstractTag tag = ((AbstractTag) parser.getResourceLocator().getEntity(name, null));
if (tag == null) {
throw new PaxmlRuntimeException("No resource found from locator: " + parser.getResourceLocator().getResourceNames());
}
return tag.printTree(0);
}
/**
* Add paxml execution listener.
*
* @param listener
* the listener
*/
public void addPaxmlExecutionListener(IExecutionListener listener) {
if (paxmlExecutionListeners == null) {
paxmlExecutionListeners = new ArrayList<IExecutionListener>(1);
}
paxmlExecutionListeners.add(listener);
}
/**
* Add entity execution listener.
*
* @param listener
* the listener
*/
public void addEntityExecutionListener(IEntityExecutionListener listener) {
if (entityExecutionListeners == null) {
entityExecutionListeners = new ArrayList<IEntityExecutionListener>(1);
}
entityExecutionListeners.add(listener);
}
/**
* Add tag execution listener.
*
* @param listener
* the listener
*/
public void addTagExecutionListener(ITagExecutionListener listener) {
if (tagExecutionListeners == null) {
tagExecutionListeners = new ArrayList<ITagExecutionListener>(1);
}
tagExecutionListeners.add(listener);
}
public Parser getParser() {
return parser;
}
public static LaunchModel executePlanFile(String planFile, Properties props) {
Resource res = PaxmlUtils.getResource(planFile, null);
LaunchModel model = new LaunchModelBuilder().build(res, props == null ? new Properties() : props);
return model;
}
public long getProcessId() {
return processId;
}
public long getSessionId() {
return sessionId;
}
}