/*
* Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
* $Id: Xml2ElementInfo.java 3918 2008-04-14 17:35:35Z gbevin $
*/
package com.uwyn.rife.engine;
import com.uwyn.rife.config.Config;
import com.uwyn.rife.config.RifeConfig;
import com.uwyn.rife.database.Datasources;
import com.uwyn.rife.engine.exceptions.EngineException;
import com.uwyn.rife.engine.exceptions.NotFoundProcessingErrorException;
import com.uwyn.rife.engine.exceptions.ParsingErrorException;
import com.uwyn.rife.engine.exceptions.ProcessingErrorException;
import com.uwyn.rife.ioc.PropertyValue;
import com.uwyn.rife.ioc.PropertyValueList;
import com.uwyn.rife.ioc.PropertyValueObject;
import com.uwyn.rife.ioc.PropertyValueParticipant;
import com.uwyn.rife.ioc.PropertyValueTemplate;
import com.uwyn.rife.ioc.exceptions.PropertyConstructionException;
import com.uwyn.rife.ioc.exceptions.PropertyValueException;
import com.uwyn.rife.resources.ResourceFinder;
import com.uwyn.rife.resources.exceptions.ResourceFinderErrorException;
import com.uwyn.rife.xml.Xml2Data;
import com.uwyn.rife.xml.exceptions.CantFindResourceException;
import com.uwyn.rife.xml.exceptions.XmlErrorException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.XMLReader;
class Xml2ElementInfo implements ElementInfoProcessor
{
private XMLReader mReader = null;
Xml2ElementInfo()
{
}
public void processElementInfo(ElementInfoBuilder builder, String declarationName, ResourceFinder resourceFinder)
throws EngineException
{
XmlElementInfoProcessor processor = new XmlElementInfoProcessor(builder);
String processed_path = null;
try
{
// process the element xml file
try
{
processed_path = declarationName;
mReader = processor.processXml(processed_path, resourceFinder, mReader);
}
catch (CantFindResourceException e)
{
processed_path = DEFAULT_ELEMENTS_PATH+declarationName;
mReader = processor.processXml(processed_path, resourceFinder, mReader);
}
}
catch (XmlErrorException e)
{
throw new ProcessingErrorException("element", declarationName, e);
}
// obtain the modification time
if (RifeConfig.Engine.getSiteAutoReload())
{
URL resource = resourceFinder.getResource(processed_path);
if (null == resource)
{
throw new NotFoundProcessingErrorException("element", processed_path, null);
}
try
{
builder.addResourceModificationTime(new UrlResource(resource, processed_path), resourceFinder.getModificationTime(resource));
}
catch (ResourceFinderErrorException e)
{
throw new ProcessingErrorException("element", declarationName, "Error while retrieving the modification time.", e);
}
}
}
}
class XmlElementInfoProcessor extends Xml2Data
{
private ElementInfoBuilder mElementInfoBuilder = null;
private StringBuilder mCharacterData = null;
private String mCurrentPropertyName = null;
private String mCurrentInput = null;
private String mCurrentOutput = null;
private String mCurrentIncookie = null;
private String mCurrentOutcookie = null;
private String mCurrentParameter = null;
private ArrayList<String> mDefaults = null;
private SubmissionBuilder mSubmissionBuilder = null;
private Stack<String> mParticipantNameStack = null;
private Stack<PropertyValueList> mPropertyValuesStack = null;
private String mCurrentTemplateType = null;
XmlElementInfoProcessor(ElementInfoBuilder builder)
{
mElementInfoBuilder = builder;
}
public ArrayList<String> getDefaults()
{
return mDefaults;
}
public void startDocument()
{
mCharacterData = null;
}
public void endDocument()
{
mCharacterData = null;
mParticipantNameStack = null;
mPropertyValuesStack = null;
}
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
{
if (qName.equals("element"))
{
mElementInfoBuilder
.setImplementation(atts.getValue("implementation"))
.extendsFrom(atts.getValue("extends"))
.setContentType(atts.getValue("contenttype"));
String pathinfo = atts.getValue("pathinfo");
if (pathinfo != null)
{
mElementInfoBuilder.setPathInfoMode(PathInfoMode.getMode(atts.getValue("pathinfo")));
}
}
else if (qName.equals("property"))
{
mCurrentPropertyName = atts.getValue("name");
mCharacterData = new StringBuilder();
mPropertyValuesStack = new Stack<PropertyValueList>();
mPropertyValuesStack.push(new PropertyValueList());
}
else if (qName.equals("participant") ||
qName.equals("datasource"))
{
// store the character data of the previous property value series
mPropertyValuesStack.peek().add(new PropertyValueObject(mCharacterData.toString()));
// initialize the new nested participant
if (null == mParticipantNameStack)
{
mParticipantNameStack = new Stack<String>();
}
mCharacterData = new StringBuilder();
String name;
if (qName.equals("datasource"))
{
name = Datasources.DEFAULT_PARTICIPANT_NAME;
}
else
{
name = atts.getValue("name");
}
mParticipantNameStack.push(name);
mPropertyValuesStack.push(new PropertyValueList());
}
else if (qName.equals("template"))
{
// store the character data of the previous property value series
mPropertyValuesStack.peek().add(new PropertyValueObject(mCharacterData.toString()));
mCurrentTemplateType = atts.getValue("type");
mCharacterData = new StringBuilder();
mPropertyValuesStack.push(new PropertyValueList());
}
else if (qName.equals("config"))
{
mCharacterData.append(Config.getRepInstance().getString(atts.getValue("param"), ""));
}
else if (qName.equals("input"))
{
mCurrentInput = atts.getValue("name");
mDefaults = new ArrayList<String>();
}
else if (qName.equals("inbean"))
{
String classname = atts.getValue("classname");
String prefix = atts.getValue("prefix");
String name = atts.getValue("name");
String group = atts.getValue("group");
mElementInfoBuilder.addInBean(classname, prefix, name, group);
}
else if (qName.equals("output"))
{
mCurrentOutput = atts.getValue("name");
mDefaults = new ArrayList<String>();
}
else if (qName.equals("outbean"))
{
String classname = atts.getValue("classname");
String prefix = atts.getValue("prefix");
String name = atts.getValue("name");
String group = atts.getValue("group");
mElementInfoBuilder.addOutBean(classname, prefix, name, group);
}
else if (qName.equals("incookie"))
{
mCurrentIncookie = atts.getValue("name");
mDefaults = new ArrayList<String>();
}
else if (qName.equals("outcookie"))
{
mCurrentOutcookie = atts.getValue("name");
mDefaults = new ArrayList<String>();
}
else if (qName.equals("childtrigger"))
{
mElementInfoBuilder.addChildTrigger(atts.getValue("name"));
}
else if (qName.equals("submission"))
{
mSubmissionBuilder = mElementInfoBuilder.enterSubmission(atts.getValue("name"));
String continuations_attr = atts.getValue("continuations");
if (continuations_attr != null)
{
mSubmissionBuilder.cancelContinuations(continuations_attr.equals("cancel"));
}
String scope_attr = atts.getValue("scope");
if (scope_attr != null)
{
mSubmissionBuilder.setScope(Scope.getScope(scope_attr));
}
}
else if (qName.equals("param"))
{
if (atts.getValue("name") != null &&
atts.getValue("regexp") != null)
{
throw new ParsingErrorException("element", getXmlPath(), "A submission parameter can't have both a name and a regexp attribute.", null);
}
if (atts.getValue("name") != null)
{
mCurrentParameter = atts.getValue("name");
mDefaults = new ArrayList<String>();
}
else if (atts.getValue("regexp") != null)
{
mSubmissionBuilder.addParameterRegexp(atts.getValue("regexp"));
mDefaults = null;
}
else
{
throw new ParsingErrorException("element", getXmlPath(), "A submission parameter needs either a name or a regexp attribute.", null);
}
}
else if (qName.equals("bean"))
{
String classname = atts.getValue("classname");
String prefix = atts.getValue("prefix");
String name = atts.getValue("name");
String group = atts.getValue("group");
mSubmissionBuilder.addBean(classname, prefix, name, group);
}
else if (qName.equals("file"))
{
if (atts.getValue("name") != null &&
atts.getValue("regexp") != null)
{
throw new ParsingErrorException("element", getXmlPath(), "A submission file can't have both a name and a regexp attribute.", null);
}
if (atts.getValue("name") != null)
{
mSubmissionBuilder.addFile(atts.getValue("name"));
}
else if (atts.getValue("regexp") != null)
{
mSubmissionBuilder.addFileRegexp(atts.getValue("regexp"));
}
else
{
throw new ParsingErrorException("element", getXmlPath(), "A submission file needs either a name or a regexp attribute.", null);
}
}
else if (qName.equals("default"))
{
mCharacterData = new StringBuilder();
}
else if (qName.equals("exit"))
{
mElementInfoBuilder.addExit(atts.getValue("name"));
}
else if (qName.equals("pathinfo"))
{
mElementInfoBuilder.addPathInfoMapping(atts.getValue("mapping"));
}
else
{
throw new ParsingErrorException("element", getXmlPath(), "Unsupport element name '"+qName+"'.", null);
}
}
public void endElement(String namespaceURI, String localName, String qName)
{
if (qName.equals("property"))
{
PropertyValueList propvals = mPropertyValuesStack.pop();
// store the character data to the current property value series
propvals.add(new PropertyValueObject(mCharacterData.toString()));
try
{
mElementInfoBuilder.addStaticProperty(mCurrentPropertyName, propvals.makePropertyValue());
}
catch (PropertyValueException e)
{
throw new PropertyConstructionException("element", getXmlPath(), mCurrentPropertyName, e);
}
mCharacterData = null;
mCurrentPropertyName = null;
mPropertyValuesStack = null;
}
else if (qName.equals("participant") ||
qName.equals("datasource"))
{
PropertyValueList propvals = mPropertyValuesStack.pop();
// store the character data to the current property value series
propvals.add(new PropertyValueObject(mCharacterData.toString()));
try
{
PropertyValue propval = new PropertyValueParticipant(mParticipantNameStack.pop(), propvals.makePropertyValue());
ArrayList<PropertyValue> containing_propval_series = mPropertyValuesStack.peek();
containing_propval_series.add(propval);
}
catch (PropertyValueException e)
{
throw new PropertyConstructionException("element", getXmlPath(), mCurrentPropertyName, e);
}
mCharacterData = new StringBuilder();
}
else if (qName.equals("template"))
{
PropertyValueList propvals = mPropertyValuesStack.pop();
// store the character data to the current property value series
propvals.add(new PropertyValueObject(mCharacterData.toString()));
try
{
PropertyValue propval = new PropertyValueTemplate(mCurrentTemplateType, propvals.makePropertyValue().getValueString());
ArrayList<PropertyValue> containing_propval_series = mPropertyValuesStack.peek();
containing_propval_series.add(propval);
}
catch (PropertyValueException e)
{
throw new PropertyConstructionException("element", getXmlPath(), mCurrentPropertyName, e);
}
mCharacterData = new StringBuilder();
}
else if (qName.equals("input"))
{
String[] defaults = null;
if (mDefaults.size() > 0)
{
defaults = new String[mDefaults.size()];
defaults = mDefaults.toArray(defaults);
}
mElementInfoBuilder.addInput(mCurrentInput, defaults);
mCurrentInput = null;
mDefaults = null;
}
else if (qName.equals("output"))
{
String[] defaults = null;
if (mDefaults.size() > 0)
{
defaults = new String[mDefaults.size()];
defaults = mDefaults.toArray(defaults);
}
mElementInfoBuilder.addOutput(mCurrentOutput, defaults);
mCurrentOutput = null;
mDefaults = null;
}
else if (qName.equals("incookie"))
{
String defaultValue = null;
if (mDefaults.size() > 0)
{
defaultValue = mDefaults.get(0);
}
mElementInfoBuilder.addIncookie(mCurrentIncookie, defaultValue);
mCurrentIncookie = null;
mDefaults = null;
}
else if (qName.equals("outcookie"))
{
String defaultValue = null;
if (mDefaults.size() > 0)
{
defaultValue = mDefaults.get(0);
}
mElementInfoBuilder.addOutcookie(mCurrentOutcookie, defaultValue);
mCurrentOutcookie = null;
mDefaults = null;
}
else if (qName.equals("submission"))
{
mSubmissionBuilder.leaveSubmission();
}
else if (qName.equals("param"))
{
if (mDefaults != null)
{
String[] defaults = null;
if (mDefaults.size() > 0)
{
defaults = new String[mDefaults.size()];
defaults = mDefaults.toArray(defaults);
}
mSubmissionBuilder.addParameter(mCurrentParameter, defaults);
}
mCurrentParameter = null;
mDefaults = null;
}
else if (qName.equals("default"))
{
if (null == mDefaults)
{
throw new ParsingErrorException("element", getXmlPath(), "A submission parameter that's defined by a regular expression can't have default values.", null);
}
mDefaults.add(mCharacterData.toString());
mCharacterData = null;
}
}
public void characters(char[] ch, int start, int length)
{
if (length > 0 &&
mCharacterData != null)
{
String text = String.copyValueOf(ch, start, length);
mCharacterData.append(text);
}
}
}