initial checkin of wcm forms management using xforms implemented by chiba. this currently uses chiba-web but will soon be replaced by our own uigenerator implemented by dojo!

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3444 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ariel Backenroth
2006-08-01 15:15:53 +00:00
parent f6355ea108
commit 33f4d911ad
202 changed files with 33626 additions and 5 deletions

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating;
import org.w3c.dom.Document;
public interface TemplateInputMethod
{
public String getInputURL(final Document xmlContent,
final TemplateType tt);
public String getSchemaInputURL(final TemplateType tt);
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating;
import java.io.Writer;
import org.w3c.dom.Document;
public interface TemplateOutputMethod
{
public void generate(final Document xmlContent,
final TemplateType tt,
final Writer out);
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating;
import org.w3c.dom.Document;
public interface TemplateType
{
public String getName();
public Document getSchema();
public Document getSampleXml(final String rootTagName);
public TemplateInputMethod[] getInputMethods();
public TemplateOutputMethod[] getOutputMethods();
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.alfresco.web.templating.xforms.*;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class TemplatingService
{
private final static TemplatingService INSTANCE = new TemplatingService();
private ArrayList<TemplateType> templateTypes =
new ArrayList<TemplateType>();
private TemplatingService()
{
}
public static TemplatingService getInstance()
{
return TemplatingService.INSTANCE;
}
public List<TemplateType> getTemplateTypes()
{
return this.templateTypes;
}
public TemplateType getTemplateType(final String name)
{
final Iterator it = this.templateTypes.iterator();
while (it.hasNext())
{
final TemplateType tt = (TemplateType)it.next();
if (tt.getName().equals(name))
return tt;
}
return null;
}
public void registerTemplateType(final TemplateType tt)
{
this.templateTypes.add(tt);
}
public TemplateType newTemplateType(final String name,
final Document schema)
{
return new TemplateTypeImpl(name, schema);
}
public void writeXML(final Node d, final File output)
{
try
{
System.out.println("writing out a document for " + d.getNodeName() +
" to " + output);
final TransformerFactory tf = TransformerFactory.newInstance();
final Transformer t = tf.newTransformer();
t.transform(new DOMSource(d), new StreamResult(output));
}
catch (TransformerException te)
{
te.printStackTrace();
assert false : te.getMessage();
}
}
public Document parseXML(final String source)
throws ParserConfigurationException,
SAXException,
IOException
{
return this.parseXML(new ByteArrayInputStream(source.getBytes()));
}
public Document parseXML(final File source)
throws ParserConfigurationException,
SAXException,
IOException
{
return this.parseXML(new FileInputStream(source));
}
public Document parseXML(final InputStream source)
throws ParserConfigurationException,
SAXException,
IOException
{
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setValidating(false);
final DocumentBuilder db = dbf.newDocumentBuilder();
final Document result = db.parse(source);
source.close();
return result;
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating.xforms;
import java.io.*;
import javax.xml.parsers.ParserConfigurationException;
import org.alfresco.util.TempFileProvider;
import org.alfresco.web.templating.*;
import org.alfresco.web.templating.xforms.schemabuilder.FormBuilderException;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.impl.xsd2inst.SampleXmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class TemplateTypeImpl
implements TemplateType
{
private final Document schema;
private final String name;
public TemplateTypeImpl(final String name,
final Document schema)
{
this.name = name;
this.schema = schema;
}
public String getName()
{
return this.name;
}
public Document getSchema()
{
return this.schema;
}
public Document getSampleXml(final String rootTagName)
{
XmlOptions xmlOptions = new XmlOptions();
xmlOptions = xmlOptions.setLoadLineNumbers().setLoadMessageDigest();
final XmlObject[] schemas = new XmlObject[1];
try
{
final File schemaFile = TempFileProvider.createTempFile("alfresco", ".schema");
TemplatingService.getInstance().writeXML(this.schema, schemaFile);
schemas[0] = XmlObject.Factory.parse(schemaFile, xmlOptions);
schemaFile.delete();
}
catch (Exception e)
{
System.err.println("Can not load schema file: " + schema + ": ");
e.printStackTrace();
}
final XmlOptions compileOptions = new XmlOptions();
compileOptions.setCompileDownloadUrls();
compileOptions.setCompileNoPvrRule();
compileOptions.setCompileNoUpaRule();
SchemaTypeSystem sts = null;
try
{
sts = XmlBeans.compileXsd(schemas,
XmlBeans.getBuiltinTypeSystem(),
compileOptions);
}
catch (XmlException xmle)
{
xmle.printStackTrace();
return null;
}
if (sts == null)
{
throw new NullPointerException("No Schemas to process.");
}
final SchemaType[] globalElems = sts.documentTypes();
SchemaType elem = null;
for (int i = 0; i < globalElems.length; i++)
{
if (rootTagName.equals(globalElems[i].getDocumentElementName().getLocalPart()))
{
elem = globalElems[i];
break;
}
}
if (elem == null)
throw new NullPointerException("Could not find a global element with name \"" + rootTagName + "\"");
final String result = SampleXmlUtil.createSampleForType(elem);
try
{
final TemplatingService ts = TemplatingService.getInstance();
return ts.parseXML(new ByteArrayInputStream(result.getBytes()));
}
catch (ParserConfigurationException pce)
{
assert false : pce.getMessage();
return null;
}
catch (SAXException saxe)
{
assert false : saxe.getMessage();
return null;
}
catch (IOException ioe)
{
assert false : ioe.getMessage();
return null;
}
}
public TemplateInputMethod[] getInputMethods()
{
return new TemplateInputMethod[] {
new XFormsInputMethod()
};
}
public TemplateOutputMethod[] getOutputMethods()
{
return new TemplateOutputMethod[0];
}
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating.xforms;
import java.io.*;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import org.alfresco.util.TempFileProvider;
import org.alfresco.web.templating.*;
import org.alfresco.web.templating.xforms.schemabuilder.*;
import org.chiba.xml.util.DOMUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
public class XFormsInputMethod
implements TemplateInputMethod
{
public XFormsInputMethod()
{
}
public String getInputURL(final Document xmlContent, final TemplateType tt)
{
try
{
final Document xform = this.getXForm(xmlContent, tt);
final String id = getDocumentElementNameNoNS(xmlContent);
// this.saveInChiba(id, xform);
final File xformFile = TempFileProvider.createTempFile("alfresco", ".xform");
final TemplatingService ts = TemplatingService.getInstance();
ts.writeXML(xform, xformFile);
final FacesContext fc = FacesContext.getCurrentInstance();
final String cp =
fc.getExternalContext().getRequestContextPath();
return cp + "/XFormsServlet?form=" + xformFile.toURI().toString();
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
public String getSchemaInputURL(final TemplateType tt)
{
try
{
// final Document xform = this.getXFormForSchema(tt);
// final File xformFile = TempFileProvider.createTempFile("alfresco", ".xform");
// final TemplatingService ts = TemplatingService.getInstance();
// ts.writeXML(tt.getSchema(), xformFile);
// final FacesContext fc = FacesContext.getCurrentInstance();
// final String cp =
// fc.getExternalContext().getRequestContextPath();
// return cp + "/XFormsServlet?form=" + xformFile.toURI().toString();
return null;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
private static String getDocumentElementNameNoNS(final Document d)
{
final Node n = d.getDocumentElement();
String name = n.getNodeName();
return name;
// String prefix = n.getPrefix();
// String namespace = n.getNamespaceURI();
// System.out.println("name " + name + " prefix " + prefix + " ns uri " + namespace);
// return name.replaceAll(".+\\:", "");
}
// public Document getXFormForSchema(final TemplateType tt)
// throws FormBuilderException
// {
// final TemplatingService ts = TemplatingService.getInstance();
//
// final File schemaFile = TempFileProvider.createTempFile("alfresco", ".schema");
// ts.writeXML(tt.getSchema(), schemaFile);
// final FacesContext fc = FacesContext.getCurrentInstance();
// final String cp =
// fc.getExternalContext().getRequestContextPath();
//
// final SchemaFormBuilder builder =
// new BaseSchemaFormBuilder("schema",
// schemaFile.toURI().toString(),
// cp + "/jsp/content/xforms/form/debug-instance.jsp",
// "post",
// new XHTMLWrapperElementsBuilder(),
// null,
// null,
// true);
// System.out.println("building xform for schema " + schemaFile.getPath());
// final Document result = builder.buildForm("/Users/arielb/Documents/alfresco/xsd/XMLSchema.xsd");
// // xmlContentFile.delete();
// // schemaFile.delete();
// return result;
// }
public Document getXForm(final Document xmlContent, final TemplateType tt)
throws FormBuilderException
{
final TemplatingService ts = TemplatingService.getInstance();
final File schemaFile = TempFileProvider.createTempFile("alfresco", ".schema");
ts.writeXML(tt.getSchema(), schemaFile);
final FacesContext fc = FacesContext.getCurrentInstance();
final String cp =
fc.getExternalContext().getRequestContextPath();
final SchemaFormBuilder builder =
new BaseSchemaFormBuilder(getDocumentElementNameNoNS(xmlContent),
xmlContent,
"http://localhost:8080" + cp + "/jsp/content/xforms/debug-instance.jsp",
"post",
new XHTMLWrapperElementsBuilder(),
null,
null,
true);
System.out.println("building xform for schema " + schemaFile.getPath());
final Document result = builder.buildForm(schemaFile.getPath());
// xmlContentFile.delete();
// schemaFile.delete();
return result;
}
// private void saveInChiba(final String fileName, final Document d)
// throws IOException
// {
// final ServletContext myContext = (ServletContext)
// FacesContext.getCurrentInstance().getExternalContext().getContext();
// final ServletContext chiba = myContext.getContext("/chiba");
// final File outputFile = new File(new File(chiba.getRealPath("/forms")),
// fileName + ".xhtml");
// TemplatingService.getInstance().writeXML(d.getDocumentElement(), outputFile);
// }
}

View File

@@ -0,0 +1,127 @@
package org.alfresco.web.templating.xforms.flux;
import org.chiba.xml.util.DOMUtil;
import org.chiba.xml.xforms.XFormsConstants;
import org.chiba.xml.xforms.events.XFormsEvent;
import org.chiba.xml.xforms.events.XFormsEventFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* EventLog logs all events happening in XForms processor and build a DOM
* document which represent those events.
*
* @author Joern Turner
* @version $Id: EventLog.java,v 1.6 2005/12/21 22:59:27 unl Exp $
*/
public class EventLog {
private static List HELPER_ELEMENTS =
Arrays.asList(new String[]
{
XFormsConstants.LABEL,
XFormsConstants.HELP,
XFormsConstants.HINT,
XFormsConstants.ALERT,
XFormsConstants.VALUE
});
private static List SELECTOR_ELEMENTS =
Arrays.asList(new String[]
{
XFormsConstants.SELECT1,
XFormsConstants.SELECT
});
private final Document doc;
private final Element root;
private Element selector;
public EventLog() {
this.doc = DOMUtil.newDocument(false, false);
this.root = this.doc.createElement("eventlog");
this.root.setAttribute("id", "eventlog");
this.doc.appendChild(this.root);
}
public Element getLog() {
return (Element) this.root.cloneNode(true);
}
public void add(XFormsEvent event) {
// get target properties
String type = event.getType();
Element target = (Element) event.getTarget();
String targetId = target.getAttributeNS(null, "id");
String targetName = target.getLocalName();
// create event element
Element element;
if (XFormsEventFactory.CHIBA_STATE_CHANGED.equals(type) && SELECTOR_ELEMENTS.contains(targetName)) {
// selector events are always appended to the end of the log
// to ensure their items' labels and values are updated before
element = insert(null, type, targetId, targetName);
if (this.selector == null)
this.selector = element;
}
else
{
// all other events are inserted before any selector events
element = insert(this.selector, type, targetId, targetName);
}
if (XFormsEventFactory.CHIBA_STATE_CHANGED.equals(type) && HELPER_ELEMENTS.contains(targetName))
{
// parent id is needed for updating all helper elements cause they
// are identified by '<parentId>-label' etc. rather than their own id
String parentId = ((Element) target.getParentNode()).getAttributeNS(null, "id");
addProperty(element, "parentId", parentId);
}
// add event params
Iterator iterator = event.getPropertyNames().iterator();
while (iterator.hasNext())
{
String name = (String) iterator.next();
addProperty(element, name, event.getContextInfo(name).toString());
}
}
public Element add(String type, String targetId, String targetName){
return insert(this.selector, type, targetId, targetName);
}
public Element addProperty(Element element, String name, String value) {
Element property = this.doc.createElement("property");
property.setAttribute("name", name);
property.appendChild(this.doc.createTextNode(value));
element.appendChild(property);
return element;
}
private Element insert(Element ref, String type, String targetId, String targetName)
{
// create event element
Element element = this.doc.createElement("event");
this.root.insertBefore(element, ref);
// add target properties
element.setAttribute("type", type);
element.setAttribute("targetId", targetId);
element.setAttribute("targetName", targetName);
return element;
}
// clean the log
public void flush()
{
DOMUtil.removeAllChildren(this.root);
this.selector = null;
}
}

View File

@@ -0,0 +1,265 @@
package org.alfresco.web.templating.xforms.flux;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.chiba.adapter.AbstractChibaAdapter;
import org.chiba.adapter.ChibaEvent;
import org.alfresco.web.templating.xforms.servlet.HttpRequestHandler;
import org.alfresco.web.templating.xforms.servlet.ServletAdapter;
import org.alfresco.web.templating.xforms.servlet.ChibaServlet;
import org.chiba.xml.xforms.events.XFormsEvent;
import org.chiba.xml.xforms.events.XFormsEventFactory;
import org.chiba.xml.xforms.exception.XFormsException;
import org.chiba.xml.xforms.ui.Repeat;
import org.chiba.xml.util.DOMUtil;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import org.w3c.dom.Element;
import javax.xml.transform.TransformerException;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
/**
* Adapter for processing DWR calls and building appropriate responses. This
* class is not exposed through DWR. Instead a Facadeclass 'FluxFacade' will be
* exposed that only allows to use the dispatch method. All other methods will
* be hidden for security.
*
* @author Joern Turner
* @version $Id: FluxAdapter.java,v 1.15 2005/12/21 22:59:27 unl Exp $
*/
public class FluxAdapter extends AbstractChibaAdapter implements EventListener {
private static final Log LOGGER = LogFactory.getLog(FluxAdapter.class);
private final HttpSession session;
private EventLog eventLog;
private EventTarget root;
public FluxAdapter(HttpSession session) {
this.chibaBean = createXFormsProcessor();
this.context = new HashMap();
chibaBean.setContext(this.context);
this.eventLog = new EventLog();
this.session = session;
}
/**
* initialize the Adapter. This is necessary cause often the using
* application will need to configure the Adapter before actually using it.
*
* @throws org.chiba.xml.xforms.exception.XFormsException
*/
public void init() throws XFormsException {
try {
// get docuent root as event target in order to capture all events
this.root = (EventTarget) this.chibaBean.getXMLContainer().getDocumentElement();
// interaction events my occur during init so we have to register before
this.root.addEventListener(XFormsEventFactory.CHIBA_LOAD_URI, this, true);
this.root.addEventListener(XFormsEventFactory.CHIBA_RENDER_MESSAGE, this, true);
this.root.addEventListener(XFormsEventFactory.CHIBA_REPLACE_ALL, this, true);
// init processor
this.chibaBean.init();
// todo: add getter for event log
setContextParam("EVENT-LOG", this.eventLog);
// register for notification events
this.root.addEventListener(XFormsEventFactory.CHIBA_STATE_CHANGED, this, true);
this.root.addEventListener(XFormsEventFactory.CHIBA_PROTOTYPE_CLONED, this, true);
this.root.addEventListener(XFormsEventFactory.CHIBA_ID_GENERATED, this, true);
this.root.addEventListener(XFormsEventFactory.CHIBA_ITEM_INSERTED, this, true);
this.root.addEventListener(XFormsEventFactory.CHIBA_ITEM_DELETED, this, true);
this.root.addEventListener(XFormsEventFactory.CHIBA_INDEX_CHANGED, this, true);
this.root.addEventListener(XFormsEventFactory.CHIBA_SWITCH_TOGGLED, this, true);
}
catch (Exception e) {
throw new XFormsException(e);
}
}
/**
* Dispatch a ChibaEvent to trigger some XForms processing such as updating
* of values or execution of triggers.
*
* @param event an application specific event
* @throws org.chiba.xml.xforms.exception.XFormsException
* @see org.chiba.adapter.DefaultChibaEventImpl
*/
public void dispatch(ChibaEvent event) throws XFormsException {
LOGGER.debug("dispatching " + event);
this.eventLog.flush();
String targetId = event.getId();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Event " + event.getEventName() + " dispatched");
LOGGER.debug("Event target: " + targetId);
// try
// {
// DOMUtil.prettyPrintDOM(this.chibaBean.getXMLContainer(), System.out);
// } catch (TransformerException e) {
// throw new XFormsException(e);
// }
}
if (event.getEventName().equals(FluxFacade.FLUX_ACTIVATE_EVENT))
chibaBean.dispatch(targetId, XFormsEventFactory.DOM_ACTIVATE);
else if (event.getEventName().equals("SETINDEX")) {
int position = Integer.parseInt((String) event.getContextInfo());
Repeat repeat = (Repeat) this.chibaBean.lookup(targetId);
repeat.setIndex(position);
}
else if (event.getEventName().equals("SETVALUE")) {
if (LOGGER.isDebugEnabled())
LOGGER.debug("Event contextinfo: " + event.getContextInfo());
this.chibaBean.updateControlValue(targetId, (String) event.getContextInfo());
}
else if (event.getEventName().equalsIgnoreCase("http-request")) {
// todo: make request handler member of web adapter
HttpRequestHandler httpRequestHandler = new HttpRequestHandler(this.chibaBean);
httpRequestHandler.execute(event);
}
else {
throw new XFormsException("Unknown or illegal event type");
}
}
/**
* listen to processor and add a DefaultChibaEventImpl object to the
* EventQueue.
*
* @param event the handled DOMEvent
*/
public void handleEvent(Event event)
{
LOGGER.debug("handleEvent(" + event + ")");
try {
if (event instanceof XFormsEvent)
{
XFormsEvent xformsEvent = (XFormsEvent) event;
String type = xformsEvent.getType();
if (XFormsEventFactory.CHIBA_REPLACE_ALL.equals(type))
{
// get event context and store it in session
Map submissionResponse = new HashMap();
submissionResponse.put("header", xformsEvent.getContextInfo("header"));
submissionResponse.put("body", xformsEvent.getContextInfo("body"));
this.session.setAttribute(ChibaServlet.CHIBA_SUBMISSION_RESPONSE, submissionResponse);
// get event properties
Element target = (Element) event.getTarget();
String targetId = target.getAttributeNS(null, "id");
String targetName = target.getLocalName();
// add event properties to log
this.eventLog.add(type, targetId, targetName);
}
else
{
// add event to log
this.eventLog.add(xformsEvent);
}
}
}
catch (Exception e) {
System.out.println("**** " + e.getMessage());
LOGGER.debug("error " + e.getMessage() + " while handling event " + event);
try {
this.chibaBean.getContainer().handleEventException(e);
}
catch (XFormsException xfe) {
xfe.printStackTrace();
}
}
}
/**
* terminates the XForms processing. right place to do cleanup of
* resources.
*
* @throws org.chiba.xml.xforms.exception.XFormsException
*/
public void shutdown() throws XFormsException {
try {
// deregister for notification events
this.root.removeEventListener(XFormsEventFactory.CHIBA_STATE_CHANGED, this, true);
this.root.removeEventListener(XFormsEventFactory.CHIBA_PROTOTYPE_CLONED, this, true);
this.root.removeEventListener(XFormsEventFactory.CHIBA_ID_GENERATED, this, true);
this.root.removeEventListener(XFormsEventFactory.CHIBA_ITEM_INSERTED, this, true);
this.root.removeEventListener(XFormsEventFactory.CHIBA_ITEM_DELETED, this, true);
this.root.removeEventListener(XFormsEventFactory.CHIBA_INDEX_CHANGED, this, true);
this.root.removeEventListener(XFormsEventFactory.CHIBA_SWITCH_TOGGLED, this, true);
// shutdown processor
this.chibaBean.shutdown();
this.chibaBean = null;
// deregister for interaction events
this.root.removeEventListener(XFormsEventFactory.CHIBA_LOAD_URI, this, true);
this.root.removeEventListener(XFormsEventFactory.CHIBA_RENDER_MESSAGE, this, true);
this.root.removeEventListener(XFormsEventFactory.CHIBA_REPLACE_ALL, this, true);
this.root = null;
System.gc();
}
catch (Exception e) {
throw new XFormsException(e);
}
}
/**
* set the upload location. This string represents the destination
* (data-sink) for uploads.
*
* @param destination a String representing the location where to store
* uploaded files/data.
*/
public void setUploadDestination(String destination) {
this.uploadDestination = destination;
//todo: this should be moved to parent class. it's duplicated in both Adapters
setContextParam(ServletAdapter.HTTP_UPLOAD_DIR, this.uploadDestination);
}
protected String escape(String string) {
if (string == null) {
return string;
}
StringBuffer buffer = new StringBuffer(string.length());
char c;
for (int index = 0; index < string.length(); index++) {
c = string.charAt(index);
switch (c) {
case '\n':
buffer.append('\\').append('n');
break;
case '\r':
buffer.append('\\').append('r');
break;
case '\t':
buffer.append('\\').append('t');
break;
case '\'':
buffer.append('\\').append('\'');
break;
case '\"':
buffer.append('\\').append('\"');
break;
default:
buffer.append(c);
break;
}
}
return buffer.toString();
}
}
// end of class

View File

@@ -0,0 +1,23 @@
package org.alfresco.web.templating.xforms.flux;
/**
* Used for signalling problems with Flux execution
*
* @author Joern Turner
* @version $Id: FluxException.java,v 1.1 2005/11/08 17:34:07 joernt Exp $
*/
public class FluxException extends Exception{
public FluxException() {
}
public FluxException(String string) {
super(string);
}
public FluxException(Throwable throwable) {
super(throwable);
}
}

View File

@@ -0,0 +1,144 @@
package org.alfresco.web.templating.xforms.flux;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.chiba.adapter.ChibaAdapter;
import org.chiba.adapter.ChibaEvent;
import org.chiba.adapter.DefaultChibaEventImpl;
import org.alfresco.web.templating.xforms.servlet.ChibaServlet;
import org.chiba.xml.util.DOMUtil;
import org.chiba.xml.xforms.exception.XFormsException;
import org.w3c.dom.Element;
import uk.ltd.getahead.dwr.ExecutionContext;
import javax.servlet.http.HttpSession;
import javax.xml.transform.TransformerException;
/**
* AJAX Facade class to hide the full functionality from the web-client.
*
* @author Joern Turner
* @version $Id: FluxFacade.java,v 1.9 2005/12/21 19:06:55 unl Exp $
*/
public class FluxFacade
{
//this is a custom event to activate a trigger in XForms.
private static final Log LOGGER = LogFactory.getLog(FluxFacade.class);
public static final String FLUX_ACTIVATE_EVENT = "flux-action-event";
ChibaAdapter adapter = null;
private HttpSession session;
/**
* grabs the actual adapter from the session.
*/
public FluxFacade() {
session = ExecutionContext.get().getSession();
adapter = (ChibaAdapter) session.getAttribute(ChibaServlet.CHIBA_ADAPTER);
}
/**
* executes a trigger
*
* @param id the id of the trigger to execute
* @return the list of events that may result through this action
* @throws FluxException
*/
public Element fireAction(String id) throws FluxException {
LOGGER.debug("fireAction " + id);
ChibaEvent chibaActivateEvent = new DefaultChibaEventImpl();
chibaActivateEvent.initEvent(FLUX_ACTIVATE_EVENT, id, null);
return dispatch(chibaActivateEvent);
}
/**
* sets the value of a control in the processor.
*
* @param id the id of the control in the host document
* @param value the new value
* @return the list of events that may result through this action
* @throws FluxException
*/
public Element setXFormsValue(String id, String value) throws FluxException {
LOGGER.debug("setXFormsValue(" + id + ", " + value + ")");
ChibaEvent event = new DefaultChibaEventImpl();
event.initEvent("SETVALUE", id, value);
return dispatch(event);
}
public Element setRepeatIndex(String id, String position) throws FluxException {
LOGGER.debug("setRepeatPosition(" + id + ", " + position + ")");
ChibaEvent event = new DefaultChibaEventImpl();
event.initEvent("SETINDEX", id, position);
return dispatch(event);
}
/**
* fetches the progress of a running upload.
*
* @param id id of the upload control in use
* @param filename filename for uploaded data
* @return a array containing two elements for evaluation in browser. First
* param is the upload control id and second will be the current
* progress of the upload.
*/
public Element fetchProgress(String id, String filename) {
String progress = "0";
if (session.getAttribute(filename) != null) {
progress = ((Integer) session.getAttribute(filename)).toString();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Percent completed: " + progress);
}
}
EventLog eventLog = (EventLog) adapter.getContextParam("EVENT-LOG");
if (eventLog == null) {
eventLog = new EventLog();
}
Element eventlogElement = eventLog.getLog();
eventLog.flush();
Element progressEvent = eventLog.add("upload-progress-event", id, "upload");
eventLog.addProperty(progressEvent, "progress", progress);
return eventlogElement;
}
private Element dispatch(ChibaEvent event) throws FluxException {
LOGGER.debug("dispatching " + event);
if (adapter != null) {
try {
adapter.dispatch(event);
}
catch (XFormsException e) {
throw new FluxException(e);
}
}
else {
//session expired or cookie got lost
throw new FluxException("Session expired. Please start again.");
}
EventLog eventLog = (EventLog) adapter.getContextParam("EVENT-LOG");
Element eventlogElement = eventLog.getLog();
if (LOGGER.isDebugEnabled()) {
try
{
DOMUtil.prettyPrintDOM(eventlogElement, System.out);
}
catch (TransformerException e)
{
e.printStackTrace();
}
}
return eventlogElement;
}
public String getInfo()
{
return "FluxFacade using " + adapter.toString();
}
}
// end of class

View File

@@ -0,0 +1,650 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating.xforms.schemabuilder;
import org.apache.xerces.xs.*;
import org.chiba.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import javax.xml.transform.Source;
import java.util.Vector;
/*
* Search for TODO for things remaining to-do in this implementation.
*
* TODO: i18n/l10n of messages, hints, captions. Possibly leverage org.chiba.i18n classes.
* TODO: When Chiba supports itemset, use schema keyref and key constraints for validation.
* TODO: Add support for default and fixed values.
* TODO: Add support for use=prohibited.
*/
/**
* A concrete base implementation of the SchemaFormBuilder interface allowing
* an XForm to be automatically generated for an XML Schema definition.
*
* @author Brian Dueck
* @version $Id: BaseSchemaFormBuilder.java,v 1.19 2005/03/29 14:24:34 unl Exp $
*/
public class BaseSchemaFormBuilder
extends AbstractSchemaFormBuilder
implements SchemaFormBuilder {
/**
* Creates a new instance of BaseSchemaForBuilder
*/
public BaseSchemaFormBuilder(String rootTagName) {
super(rootTagName);
}
/**
* Creates a new BaseSchemaFormBuilder object.
*
* @param rootTagName __UNDOCUMENTED__
* @param instanceSource __UNDOCUMENTED__
* @param action __UNDOCUMENTED__
* @param submitMethod __UNDOCUMENTED__
* @param wrapper __UNDOCUMENTED__
* @param stylesheet __UNDOCUMENTED__
*/
public BaseSchemaFormBuilder(String rootTagName,
Source instanceSource,
String action,
String submitMethod,
WrapperElementsBuilder wrapper,
String stylesheet,
String base,
boolean userSchemaTypes) {
super(rootTagName,
instanceSource,
action,
submitMethod,
wrapper,
stylesheet,
base,
userSchemaTypes);
}
/**
* Creates a new BaseSchemaFormBuilder object.
*
* @param rootTagName __UNDOCUMENTED__
* @param instanceSource __UNDOCUMENTED__
* @param action __UNDOCUMENTED__
* @param submitMethod __UNDOCUMENTED__
* @param wrapper __UNDOCUMENTED__
* @param stylesheet __UNDOCUMENTED__
*/
public BaseSchemaFormBuilder(String rootTagName,
Document instanceDocument,
String action,
String submitMethod,
WrapperElementsBuilder wrapper,
String stylesheet,
String base,
boolean userSchemaTypes) {
super(rootTagName,
instanceDocument,
action,
submitMethod,
wrapper,
stylesheet,
base,
userSchemaTypes);
}
/**
* Creates a new BaseSchemaFormBuilder object.
*
* @param rootTagName __UNDOCUMENTED__
* @param instanceHref __UNDOCUMENTED__
* @param action __UNDOCUMENTED__
* @param submitMethod __UNDOCUMENTED__
* @param wrapper __UNDOCUMENTED__
* @param stylesheet __UNDOCUMENTED__
*/
public BaseSchemaFormBuilder(String rootTagName,
String instanceHref,
String action,
String submitMethod,
WrapperElementsBuilder wrapper,
String stylesheet,
String base,
boolean userSchemaTypes) {
super(rootTagName,
instanceHref,
action,
submitMethod,
wrapper,
stylesheet,
base,
userSchemaTypes);
}
/**
* __UNDOCUMENTED__
*
* @param text __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public String createCaption(String text) {
return StringUtil.capitalizeIdentifier(text);
}
/**
* __UNDOCUMENTED__
*
* @param attribute __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public String createCaption(XSAttributeDeclaration attribute) {
// TODO: Improve i18n/l10n of caption - may have to use
// a custom <appinfo> element in the XML Schema to do this.
//
return createCaption(attribute.getName());
}
public String createCaption(XSAttributeUse attribute) {
// TODO: Improve i18n/l10n of caption - may have to use
// a custom <appinfo> element in the XML Schema to do this.
//
return createCaption(attribute.getAttrDeclaration().getName());
}
/**
* __UNDOCUMENTED__
*
* @param element __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public String createCaption(XSElementDeclaration element) {
// TODO: Improve i18n/l10n of caption - may have to use
// a custom <appinfo> element in the XML Schema to do this.
//
return createCaption(element.getName());
}
/**
* __UNDOCUMENTED__
*
* @param element __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public String createCaption(XSObject element) {
// TODO: Improve i18n/l10n of caption - may have to use
// a custom <appinfo> element in the XML Schema to do this.
//
if (element instanceof XSElementDeclaration) {
return createCaption(((XSElementDeclaration) element).getName());
} else if (element instanceof XSAttributeDeclaration) {
return createCaption(((XSAttributeDeclaration) element).getName());
} else if (element instanceof XSAttributeUse) {
return createCaption(((XSAttributeUse) element).getAttrDeclaration().getName());
} else
LOGGER.warn("WARNING: createCaption: element is not an attribute nor an element: "
+ element.getClass().getName());
return null;
}
/**
* __UNDOCUMENTED__
*
* @param xForm __UNDOCUMENTED__
* @param caption __UNDOCUMENTED__
* @param controlType __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public Element createControlForAnyType(Document xForm,
String caption,
XSTypeDefinition controlType) {
Element control =
xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "textarea");
this.setXFormsId(control);
control.setAttributeNS(CHIBA_NS, getChibaNSPrefix() + "height", "3");
//label
Element captionElement =
(Element) control.appendChild(xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "label"));
this.setXFormsId(captionElement);
captionElement.appendChild(xForm.createTextNode(caption));
return control;
}
/**
* __UNDOCUMENTED__
*
* @param xForm __UNDOCUMENTED__
* @param caption __UNDOCUMENTED__
* @param controlType __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public Element createControlForAtomicType(Document xForm,
String caption,
XSSimpleTypeDefinition controlType) {
Element control;
//remove while select1 do not work correctly in repeats
if ((controlType.getName() != null)
&& controlType.getName().equals("boolean")) {
control =
xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "select1");
control.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "appearance",
"full");
this.setXFormsId(control);
Element item_true =
xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "item");
this.setXFormsId(item_true);
Element label_true =
xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "label");
this.setXFormsId(label_true);
Text label_true_text = xForm.createTextNode("true");
label_true.appendChild(label_true_text);
item_true.appendChild(label_true);
Element value_true =
xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "value");
this.setXFormsId(value_true);
Text value_true_text = xForm.createTextNode("true");
value_true.appendChild(value_true_text);
item_true.appendChild(value_true);
control.appendChild(item_true);
Element item_false =
xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "item");
this.setXFormsId(item_false);
Element label_false =
xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "label");
this.setXFormsId(label_false);
Text label_false_text = xForm.createTextNode("false");
label_false.appendChild(label_false_text);
item_false.appendChild(label_false);
Element value_false =
xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "value");
this.setXFormsId(value_false);
Text value_false_text = xForm.createTextNode("false");
value_false.appendChild(value_false_text);
item_false.appendChild(value_false);
control.appendChild(item_false);
} else {
control =
xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "input");
this.setXFormsId(control);
}
//label
Element captionElement =
(Element) control.appendChild(xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "label"));
this.setXFormsId(captionElement);
captionElement.appendChild(xForm.createTextNode(caption));
return control;
}
/**
* __UNDOCUMENTED__
*
* @param xForm __UNDOCUMENTED__
* @param controlType __UNDOCUMENTED__
* @param caption __UNDOCUMENTED__
* @param bindElement __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public Element createControlForEnumerationType(Document xForm,
XSSimpleTypeDefinition controlType,
String caption,
Element bindElement) {
// TODO: Figure out an intelligent or user determined way to decide between
// selectUI style (listbox, menu, combobox, radio) (radio and listbox best apply)
// Possibly look for special appInfo section in the schema and if not present default to comboBox...
//
// For now, use radio if enumValues < DEFAULT_LONG_LIST_MAX_SIZE otherwise use combobox
//
StringList enumFacets = controlType.getLexicalEnumeration();
int nbFacets = enumFacets.getLength();
if (nbFacets > 0) {
Vector enumValues = new Vector();
Element control =
xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "select1");
this.setXFormsId(control);
//label
Element captionElement1 =
(Element) control.appendChild(xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "label"));
this.setXFormsId(captionElement1);
captionElement1.appendChild(xForm.createTextNode(caption));
Element choices =
xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "choices");
this.setXFormsId(choices);
for (int i = 0; i < nbFacets; i++) {
String facet = enumFacets.item(i);
enumValues.add(facet);
}
if (nbFacets
< Long.parseLong(getProperty(SELECTONE_LONG_LIST_SIZE_PROP))) {
control.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "appearance",
getProperty(SELECTONE_UI_CONTROL_SHORT_PROP));
} else {
control.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "appearance",
getProperty(SELECTONE_UI_CONTROL_LONG_PROP));
// add the "Please select..." instruction item for the combobox
// and set the isValid attribute on the bind element to check for the "Please select..."
// item to indicate that is not a valid value
//
{
String pleaseSelect = "[Select1 " + caption + "]";
Element item =
xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "item");
this.setXFormsId(item);
choices.appendChild(item);
Element captionElement =
xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "label");
this.setXFormsId(captionElement);
item.appendChild(captionElement);
captionElement.appendChild(xForm.createTextNode(pleaseSelect));
Element value =
xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "value");
this.setXFormsId(value);
item.appendChild(value);
value.appendChild(xForm.createTextNode(pleaseSelect));
// not(purchaseOrder/state = '[Choose State]')
//String isValidExpr = "not(" + bindElement.getAttributeNS(XFORMS_NS,"nodeset") + " = '" + pleaseSelect + "')";
// ->no, not(. = '[Choose State]')
String isValidExpr = "not( . = '" + pleaseSelect + "')";
//check if there was a constraint
String constraint =
bindElement.getAttributeNS(XFORMS_NS, "constraint");
if ((constraint != null) && !constraint.equals("")) {
constraint = constraint + " and " + isValidExpr;
} else {
constraint = isValidExpr;
}
bindElement.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "constraint",
constraint);
}
}
control.appendChild(choices);
addChoicesForSelectControl(xForm, choices, enumValues);
return control;
} else {
return null;
}
}
/**
* __UNDOCUMENTED__
*
* @param xForm __UNDOCUMENTED__
* @param listType __UNDOCUMENTED__
* @param caption __UNDOCUMENTED__
* @param bindElement __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public Element createControlForListType(Document xForm,
XSSimpleTypeDefinition listType,
String caption,
Element bindElement) {
XSSimpleTypeDefinition controlType = listType.getItemType();
StringList enumFacets = controlType.getLexicalEnumeration();
int nbFacets = enumFacets.getLength();
if (nbFacets > 0) {
Element control =
xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "select");
this.setXFormsId(control);
//label
Element captionElement =
(Element) control.appendChild(xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "label"));
this.setXFormsId(captionElement);
captionElement.appendChild(xForm.createTextNode(caption));
Vector enumValues = new Vector();
for (int i = 0; i < nbFacets; i++) {
String facet = enumFacets.item(i);
enumValues.add(facet);
}
// TODO: Figure out an intelligent or user determined way to decide between
// selectUI style (listbox, menu, combobox, radio) (radio and listbox best apply)
// Possibly look for special appInfo section in the schema and if not present default to checkBox...
//
// For now, use checkbox if there are < DEFAULT_LONG_LIST_MAX_SIZE items, otherwise use long control
//
if (enumValues.size()
< Long.parseLong(getProperty(SELECTMANY_LONG_LIST_SIZE_PROP))) {
control.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "appearance",
getProperty(SELECTMANY_UI_CONTROL_SHORT_PROP));
} else {
control.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "appearance",
getProperty(SELECTMANY_UI_CONTROL_LONG_PROP));
}
Element choices =
xForm.createElementNS(XFORMS_NS,
getXFormsNSPrefix() + "choices");
this.setXFormsId(choices);
control.appendChild(choices);
addChoicesForSelectControl(xForm, choices, enumValues);
return control;
} else {
return null;
}
}
/**
* __UNDOCUMENTED__
*
* @param xForm __UNDOCUMENTED__
* @param node __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public Element createHint(Document xForm, XSObject node) {
XSAnnotation annotation = null;
if (node instanceof XSElementDeclaration)
annotation = ((XSElementDeclaration) node).getAnnotation();
else if (node instanceof XSAttributeDeclaration)
annotation = ((XSAttributeDeclaration) node).getAnnotation();
else if (node instanceof XSAttributeUse)
annotation =
((XSAttributeUse) node).getAttrDeclaration().getAnnotation();
if (annotation != null)
return addHintFromDocumentation(xForm, annotation);
else
return null;
}
/**
* __UNDOCUMENTED__
*
* @param bindElement __UNDOCUMENTED__
*/
public void endBindElement(Element bindElement) {
return;
}
/**
* __UNDOCUMENTED__
*
* @param controlElement __UNDOCUMENTED__
* @param controlType __UNDOCUMENTED__
*/
public void endFormControl(Element controlElement,
XSTypeDefinition controlType,
int minOccurs,
int maxOccurs) {
return;
}
/**
* __UNDOCUMENTED__
*
* @param groupElement __UNDOCUMENTED__
*/
public void endFormGroup(Element groupElement,
XSTypeDefinition controlType,
int minOccurs,
int maxOccurs,
Element modelSection) {
return;
}
/**
* __UNDOCUMENTED__
*
* @param bindElement __UNDOCUMENTED__
* @param controlType __UNDOCUMENTED__
* @param minOccurs __UNDOCUMENTED__
* @param maxOccurs __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public Element startBindElement(Element bindElement,
XSTypeDefinition controlType,
int minOccurs,
int maxOccurs) {
// START WORKAROUND
// Due to a Chiba bug, anyType is not a recognized type name.
// so, if this is an anyType, then we'll just skip the type
// setting.
//
// type.getName() may be 'null' for anonymous types, so compare against
// static string (see bug #1172541 on sf.net)
if (!("anyType").equals(controlType.getName())) {
Element enveloppe = bindElement.getOwnerDocument().getDocumentElement();
String typeName = this.getXFormsTypeName(enveloppe, controlType);
if (typeName != null && !typeName.equals(""))
bindElement.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "type",
typeName);
}
if (minOccurs == 0) {
bindElement.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "required",
"false()");
} else {
bindElement.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "required",
"true()");
}
//no more minOccurs & maxOccurs element: add a constraint if maxOccurs>1:
//count(.) <= maxOccurs && count(.) >= minOccurs
String minConstraint = null;
String maxConstraint = null;
if (minOccurs > 1) {
//if 0 or 1 -> no constraint (managed by "required")
minConstraint = "count(.) >= " + minOccurs;
}
if (maxOccurs > 1) {
//if 1 or unbounded -> no constraint
maxConstraint = "count(.) <= " + maxOccurs;
}
String constraint = null;
if ((minConstraint != null) && (maxConstraint != null)) {
constraint = minConstraint + " and " + maxConstraint;
} else if (minConstraint != null) {
constraint = minConstraint;
} else {
constraint = maxConstraint;
}
if ((constraint != null) && !constraint.equals("")) {
bindElement.setAttributeNS(XFORMS_NS,
getXFormsNSPrefix() + "constraint",
constraint);
}
/*if (minOccurs != 1) {
bindElement.setAttributeNS(XFORMS_NS,getXFormsNSPrefix() + "minOccurs",String.valueOf(minOccurs));
}
if (maxOccurs != 1) {
bindElement.setAttributeNS(XFORMS_NS,getXFormsNSPrefix() + "maxOccurs",maxOccurs == -1 ? "unbounded" : String.valueOf((maxOccurs)));
}*/
return bindElement;
}
/**
* __UNDOCUMENTED__
*
* @param controlElement __UNDOCUMENTED__
* @param controlType __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public Element startFormControl(Element controlElement,
XSTypeDefinition controlType) {
return controlElement;
}
/**
* __UNDOCUMENTED__
*
* @param groupElement __UNDOCUMENTED__
* @param schemaElement __UNDOCUMENTED__
* @return __UNDOCUMENTED__
*/
public Element startFormGroup(Element groupElement,
XSElementDeclaration schemaElement) {
//groupElement.setAttributeNS(CHIBA_NS,getChibaNSPrefix() + "box-align",getProperty(GROUP_BOX_ALIGN_PROP));
//groupElement.setAttributeNS(CHIBA_NS,getChibaNSPrefix() + "box-orient",getProperty(GROUP_BOX_ORIENT_PROP));
//groupElement.setAttributeNS(CHIBA_NS,getChibaNSPrefix() + "caption-width",getProperty(GROUP_CAPTION_WIDTH_PROP));
//groupElement.setAttributeNS(CHIBA_NS,getChibaNSPrefix() + "width",getProperty(GROUP_WIDTH_PROP));
//groupElement.setAttributeNS(CHIBA_NS,getChibaNSPrefix() + "border",getProperty(GROUP_BORDER_PROP));
return groupElement;
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating.xforms.schemabuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Basic implementation of WrapperElementsBuilder, with no additional design
*
* @author - Sophie Ramel
*/
public class BaseWrapperElementsBuilder implements WrapperElementsBuilder {
/**
* Creates a new instance of BaseWrapperElementsBuilder
*/
public BaseWrapperElementsBuilder() {
}
/**
* create the wrapper element of the different controls
*
* @param controlElement the control element (input, select, repeat, group, ...)
* @return the wrapper element, already containing the control element
*/
public Element createControlsWrapper(Element controlElement) {
return controlElement;
}
/**
* creates the global enveloppe of the resulting document, and puts it in the document
*
* @return the enveloppe
*/
public Element createEnvelope(Document xForm) {
Element envelopeElement = xForm.createElement("envelope");
//Element envelopeElement = xForm.createElementNS(CHIBA_NS, this.getChibaNSPrefix()+"envelope");
xForm.appendChild(envelopeElement);
return envelopeElement;
}
/**
* create the wrapper element of the form
*
* @param enveloppeElement the form element (chiba:form or other)
* @return the wrapper element
*/
public Element createFormWrapper(Element enveloppeElement) {
//add a "body" element without NS
Document doc = enveloppeElement.getOwnerDocument();
Element body = doc.createElement("body");
//body.appendChild(formElement);
enveloppeElement.appendChild(body);
return body;
}
/**
* create the element that will contain the content of the group (or repeat) element
*
* @param groupElement the group or repeat element
* @return the wrapper element, already containing the content of the group element
*/
public Element createGroupContentWrapper(Element groupElement) {
return groupElement;
}
/**
* create the wrapper element of the xforms:model element
*
* @param modelElement the xforms:model element
* @return the wrapper element, already containing the model
*/
public Element createModelWrapper(Element modelElement) {
return modelElement;
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating.xforms.schemabuilder;
/**
* This exception is thrown when implementations of <code>SchemaFormBuilder</code> encounters an
* error building a form.
*
* @author Brian Dueck
* @version $Id: FormBuilderException.java,v 1.4 2005/01/31 22:49:31 joernt Exp $
*/
public class FormBuilderException extends java.lang.Exception {
private Exception cause = null;
/**
* Creates a new instance of <code>FormBuilderException</code> without detail message.
*/
public FormBuilderException() {
}
/**
* Constructs an instance of <code>FormBuilderException</code> with the specified detail message.
*
* @param msg the detail message.
*/
public FormBuilderException(String msg) {
super(msg);
}
/**
* Constructs an instance of <code>FormBuilderException</code> with the specified root exception.
*
* @param x The root exception.
*/
public FormBuilderException(Exception x) {
//THIS DOES NOT WORK WITH JDK 1.3 CAUSE THIS IS NEW IN JDK 1.4
//super(x);
super(x.getMessage());
}
}
/*
$Log: FormBuilderException.java,v $
Revision 1.4 2005/01/31 22:49:31 joernt
added copyright notice
Revision 1.3 2004/08/15 14:14:07 joernt
preparing release...
-reformatted sources to fix mixture of tabs and spaces
-optimized imports on all files
Revision 1.2 2003/10/02 15:15:49 joernt
applied chiba jalopy settings to whole src tree
Revision 1.1 2003/07/12 12:22:48 joernt
package refactoring: moved from xforms.builder
Revision 1.1.1.1 2003/05/23 14:54:08 unl
no message
Revision 1.2 2003/02/19 09:09:15 soframel
print the exception's message
Revision 1.1 2002/12/11 14:50:42 soframel
transferred the Schema2XForms generator from chiba2 to chiba1
Revision 1.3 2002/06/11 17:13:03 joernt
commented out jdk 1.3 incompatible constructor-impl
Revision 1.2 2002/06/11 14:06:31 joernt
commented out the jdk 1.4 constructor
Revision 1.1 2002/05/22 22:24:34 joernt
Brian's initial version of schema2xforms builder
*/

View File

@@ -0,0 +1,420 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating.xforms.schemabuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xerces.xs.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.transform.Source;
import java.util.Properties;
/**
* An object that implements this interface can build an XForm that conforms to
* the elements and attributes declared in an XML Schema.
*
* @author Brian Dueck
* @version $Id: SchemaFormBuilder.java,v 1.16 2005/02/10 13:24:57 joernt Exp $
*/
public interface SchemaFormBuilder {
public final static Log LOGGER =
LogFactory.getLog(SchemaFormBuilder.class);
/**
* XMLSchema Instance Namespace declaration
*/
public static final String XMLSCHEMA_INSTANCE_NAMESPACE_URI = "http://www.w3.org/2001/XMLSchema-instance";
/**
* XMLNS Namespace declaration.
*/
public static final String XMLNS_NAMESPACE_URI =
"http://www.w3.org/2000/xmlns/";
/**
* XML Namespace declaration
*/
public static final String XML_NAMESPACE_URI =
"http://www.w3.org/XML/1998/namespace";
/**
* XForms namespace declaration.
*/
public static final String XFORMS_NS = "http://www.w3.org/2002/xforms";
/**
* Chiba namespace declaration.
*/
public static final String CHIBA_NS =
"http://chiba.sourceforge.net/xforms";
/**
* XLink namespace declaration.
*/
public static final String XLINK_NS = "http://www.w3.org/1999/xlink";
/**
* XML Events namsepace declaration.
*/
public static final String XMLEVENTS_NS = "http://www.w3.org/2001/xml-events";
/**
* Chiba prefix
*/
public static final String chibaNSPrefix = "chiba:";
/**
* XForms prefix
*/
public static final String xformsNSPrefix = "xforms:";
/**
* Xlink prefix
*/
public static final String xlinkNSPrefix = "xlink:";
/**
* XMLSchema instance prefix *
*/
public static final String xmlSchemaInstancePrefix = "xsi:";
/**
* XML Events prefix
*/
public static final String xmleventsNSPrefix = "ev:";
/**
* __UNDOCUMENTED__
*
* @return __UNDOCUMENTED__
*/
public String getAction();
/**
* __UNDOCUMENTED__
*
* @return __UNDOCUMENTED__
*/
public String getInstanceHref();
/**
* __UNDOCUMENTED__
*
* @return __UNDOCUMENTED__
*/
public int getInstanceMode();
/**
* __UNDOCUMENTED__
*
* @return __UNDOCUMENTED__
*/
public Source getInstanceSource();
/**
* __UNDOCUMENTED__
*
* @return __UNDOCUMENTED__
*/
public Document getInstanceDocument();
/**
* Get the current set of properties used by implementations of SchemaFormBuilder.
*
* @return The list of properties.
*/
public Properties getProperties();
/**
* Sets the property to the specified value. If the property exists, its value is overwritten.
*
* @param key The implementation defined property key.
* @param value The value for the property.
*/
public void setProperty(String key, String value);
/**
* Gets the value for the specified property.
*
* @param key The implementation defined property key.
* @return The property value if found, or null if the property cannot be located.
*/
public String getProperty(String key);
/**
* Gets the value for the specified property, with a default if the property cannot be located.
*
* @param key The implementation defined property key.
* @param defaultValue This value will be returned if the property does not exists.
* @return The property value if found, or defaultValue if the property cannot be located.
*/
public String getProperty(String key, String defaultValue);
/**
* Properties choosed by the user
*/
public String getRootTagName();
/**
* __UNDOCUMENTED__
*
* @return __UNDOCUMENTED__
*/
public String getStylesheet();
/**
* __UNDOCUMENTED__
*
* @return __UNDOCUMENTED__
*/
public String getSubmitMethod();
/**
* Generate the XForm based on a user supplied XML Schema.
*
* @param inputURI The document source for the XML Schema.
* @return The Document containing the XForm.
* @throws org.chiba.tools.schemabuilder.FormBuilderException
* If an error occurs building the XForm.
*/
public Document buildForm(String inputURI) throws FormBuilderException;
/**
* Creates a caption for the provided text extracted from the XML Schema.
* The implementation is responsible for reformatting the provided string to make it
* suitable to be displayed to users of the XForm. This typically includes translating
* XML tag name style identifiers (e.g. customerStreetAddress) into more reader friendly
* captions (e.g. Customer Street Address).
*
* @param text The string value to be reformatted for use as a caption.
* @return The caption.
*/
public String createCaption(String text);
/**
* Creates a caption for the provided XML Schema attribute.
* The implementation is responsible for providing an appropriate caption
* suitable to be displayed to users of the XForm. This typically includes translating
* XML tag name style identifiers (e.g. customerStreetAddress) into more reader friendly
* captions (e.g. Customer Street Address).
*
* @param attribute The XML schema attribute for which a caption is required.
* @return The caption.
*/
public String createCaption(XSAttributeDeclaration attribute);
/**
* Creates a caption for the provided XML Schema element.
* The implementation is responsible for providing an appropriate caption
* suitable to be displayed to users of the XForm. This typically includes translating
* XML tag name style identifiers (e.g. customerStreetAddress) into more reader friendly
* captions (e.g. Customer Street Address).
*
* @param element The XML schema element for which a caption is required.
* @return The caption.
*/
public String createCaption(XSElementDeclaration element);
/**
* Creates a form control for an XML Schema any type.
* <p/>
* This method is called when the form builder determines a form control is required for
* an any type.
* The implementation of this method is responsible for creating an XML element of the
* appropriate type to receive a value for <b>controlType</b>. The caller is responsible
* for adding the returned element to the form and setting caption, bind, and other
* standard elements and attributes.
*
* @param xForm The XForm document.
* @param controlType The XML Schema type for which the form control is to be created.
* @return The element for the form control.
*/
public Element createControlForAnyType(Document xForm,
String caption,
XSTypeDefinition controlType);
/**
* Creates a form control for an XML Schema simple atomic type.
* <p/>
* This method is called when the form builder determines a form control is required for
* an atomic type.
* The implementation of this method is responsible for creating an XML element of the
* appropriate type to receive a value for <b>controlType</b>. The caller is responsible
* for adding the returned element to the form and setting caption, bind, and other
* standard elements and attributes.
*
* @param xForm The XForm document.
* @param controlType The XML Schema type for which the form control is to be created.
* @return The element for the form control.
*/
public Element createControlForAtomicType(Document xForm,
String caption,
XSSimpleTypeDefinition controlType);
/**
* Creates a form control for an XML Schema simple type restricted by an enumeration.
* This method is called when the form builder determines a form control is required for
* an enumerated type.
* The implementation of this method is responsible for creating an XML element of the
* appropriate type to receive a value for <b>controlType</b>. The caller is responsible
* for adding the returned element to the form and setting caption, bind, and other
* standard elements and attributes.
*
* @param xForm The XForm document.
* @param controlType The XML Schema type for which the form control is to be created.
* @param caption The caption for the form control. The caller The purpose of providing the caption
* is to permit the implementation to add a <b>[Select1 .... ]</b> message that involves the caption.
* @param bindElement The bind element for this control. The purpose of providing the bind element
* is to permit the implementation to add a isValid attribute to the bind element that prevents
* the <b>[Select1 .... ]</b> item from being selected.
* @return The element for the form control.
*/
public Element createControlForEnumerationType(Document xForm,
XSSimpleTypeDefinition controlType,
String caption,
Element bindElement);
/**
* Creates a form control for an XML Schema simple list type.
* <p/>
* This method is called when the form builder determines a form control is required for
* a list type.
* The implementation of this method is responsible for creating an XML element of the
* appropriate type to receive a value for <b>controlType</b>. The caller is responsible
* for adding the returned element to the form and setting caption, bind, and other
* standard elements and attributes.
*
* @param xForm The XForm document.
* @param listType The XML Schema list type for which the form control is to be created.
* @param caption The caption for the form control. The caller The purpose of providing the caption
* is to permit the implementation to add a <b>[Select1 .... ]</b> message that involves the caption.
* @param bindElement The bind element for this control. The purpose of providing the bind element
* is to permit the implementation to add a isValid attribute to the bind element that prevents
* the <b>[Select1 .... ]</b> item from being selected.
* @return The element for the form control.
*/
public Element createControlForListType(Document xForm,
XSSimpleTypeDefinition listType,
String caption,
Element bindElement);
/**
* Creates a hint XML Schema annotated node (AttributeDecl or ElementDecl).
* The implementation is responsible for providing an xforms:hint element for the
* specified schemaNode suitable to be dsipalayed to users of the XForm. The caller
* is responsible for adding the returned element to the form.
* This typically includes extracting documentation from the element/attribute's
* annotation/documentation elements and/or extracting the same information from the
* element/attribute's type annotation/documentation.
*
* @param schemaNode The string value to be reformatted for use as a caption.
* @return The xforms:hint element. If a null value is returned a hint is not added.
*/
public Element createHint(Document xForm, XSObject schemaNode);
/**
* This method is invoked after the form builder is finished creating and processing
* a bind element. Implementations may choose to use this method to add/inspect/modify
* the bindElement prior to the builder moving onto the next bind element.
*
* @param bindElement The bind element being processed.
*/
public void endBindElement(Element bindElement);
/**
* This method is invoked after the form builder is finished creating and processing
* a form control. Implementations may choose to use this method to add/inspect/modify
* the controlElement prior to the builder moving onto the next control.
*
* @param controlElement The form control element that was created.
* @param controlType The XML Schema type for which <b>controlElement</b> was created.
*/
public void endFormControl(Element controlElement,
XSTypeDefinition controlType,
int minOccurs,
int maxOccurs);
/**
* __UNDOCUMENTED__
*
* @param groupElement __UNDOCUMENTED__
*/
public void endFormGroup(Element groupElement,
XSTypeDefinition controlType,
int minOccurs,
int maxOccurs,
Element modelSection);
/**
* Reset the SchemaFormBuilder to default values.
*/
public void reset();
/**
* This method is invoked after an xforms:bind element is created for the specified SimpleType.
* The implementation is responsible for setting setting any/all bind attributes
* except for <b>id</b> and <b>ref</b> - these have been automatically set
* by the caller (and should not be touched by implementation of startBindElement)
* prior to invoking startBindElement.
* The caller automatically adds the returned element to the model section of
* the form.
*
* @param bindElement The bindElement being processed.
* @param controlType XML Schema type of the element/attribute this bind is for.
* @param minOccurs The minimum number of occurences for this element/attribute.
* @param maxOccurs The maximum number of occurences for this element/attribute.
* @return The bind Element to use in the XForm - bindElement or a replacement.
*/
public Element startBindElement(Element bindElement,
XSTypeDefinition controlType,
int minOccurs,
int maxOccurs);
/**
* This method is invoked after the form builder creates a form control
* via a createControlForXXX() method but prior to decorating the form control
* with common attributes such as a caption, hint, help text elements,
* bind attributes, etc.
* The returned element is used in the XForm in place of controlElement.
* Implementations may choose to use this method to substitute controlElement
* with a different element, or perform any other processing on controlElement
* prior to it being added to the form.
*
* @param controlElement The form control element that was created.
* @param controlType The XML Schema type for which <b>controlElement</b> was created.
* @return The Element to use in the XForm - controlElement or a replacement.
*/
public Element startFormControl(Element controlElement,
XSTypeDefinition controlType);
/**
* This method is invoked after an xforms:group element is created for the specified
* ElementDecl. A group is created whenever an element is encountered in the XML Schema
* that contains other elements and attributes (complex types or mixed content types).
* The caller automatically adds the returned element to the XForm.
*
* @param groupElement The groupElement being processed.
* @param schemaElement The schemaElement for the group.
* @return The group Element to use in the XForm - groupElement or a replacement. If a null
* value is returned, the group is not created.
*/
public Element startFormGroup(Element groupElement,
XSElementDeclaration schemaElement);
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating.xforms.schemabuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* This interface provides methods to create the "wrappers" elements that will contain the XForms document.
* These elements can be:
* - the first "enveloppe" element
* - other elements specific to a destination language or platform (ex: XHTML tags)
*
* @author Sophie Ramel
*/
public interface WrapperElementsBuilder {
/**
* create the wrapper element of the form (exemple_ "body" for HTML)
*
* @param enveloppeElement the containing enveloppe
* @return the wrapper element, already added in the enveloppe
*/
public Element createFormWrapper(Element enveloppeElement);
/**
* create the wrapper element of the different controls
*
* @param controlElement the control element (input, select, repeat, group, ...)
* @return the wrapper element, already containing the control element
*/
public Element createControlsWrapper(Element controlElement);
/**
* creates the global enveloppe of the resulting document, and puts it in the document
*
* @return the enveloppe
*/
public Element createEnvelope(Document xForm);
/**
* create the element that will contain the content of the group (or repeat) element
*
* @param groupElement the group or repeat element
* @return - the wrapper element, already containing the content of the group element
*/
public Element createGroupContentWrapper(Element groupElement);
/**
* create the wrapper element of the xforms:model element
*
* @param modelElement the xforms:model element
* @return - the wrapper element, already containing the model
*/
public Element createModelWrapper(Element modelElement);
}

View File

@@ -0,0 +1,230 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.templating.xforms.schemabuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
/**
* XHTML implementation of WrapperElementsBuilder: allows to wrap the XForm document in XHTML tags.
*
* @author Sophie Ramel
*/
public class XHTMLWrapperElementsBuilder implements WrapperElementsBuilder {
private final static String XHTML_NS = "http://www.w3.org/1999/xhtml";
private final static String XHTML_PREFIX = "xhtml";
// private final static String XHTML_NS = "http://www.w3.org/2002/06/xhtml2";
// private final static String XHTML_PREFIX = "html";
private String title;
private final Vector links = new Vector();
private final Vector meta = new Vector();
private final Hashtable namespaces = new Hashtable();
/**
* Creates a new instance of XHTMLWrapperElementsBuilder
*/
public XHTMLWrapperElementsBuilder() { }
/**
* add a tag "title" in the header of the HTML document
*/
public void setTitle(String title) {
this.title = title;
}
/**
* add a tag "link" in the header of the HTML document
*
* @param href the "href" parameter of the "link" tag
* @param type the "type" parameter of the "link" tag
* @param rel the "rel" parameter of the "link" tag
*/
public void addLink(String href, String type, String rel) {
String[] l = { href, type, rel };
links.add(l);
}
/**
* add a tag "meta" in the header of the HTML document
*
* @param http_equiv the "http-equiv" parameter of the "META" tag
* @param name the "name" parameter of the "META" tag
* @param content the "content" parameter of the "META" tag
* @param scheme the "scheme" parameter of the "META" tag
*/
public void addMeta(String http_equiv,
String name,
String content,
String scheme) {
String[] s = new String[] { http_equiv, name, content, scheme};
meta.add(s);
}
public void addNamespaceDeclaration(String prefix, String url) {
namespaces.put(prefix, url);
}
/**
* create the wrapper element of the different controls
*
* @param controlElement the control element (input, select, repeat, group, ...)
* @return the wrapper element, already containing the control element
*/
public Element createControlsWrapper(Element controlElement) {
return controlElement;
}
/**
* creates the global enveloppe of the resulting document, and puts it in the document
*
* @return the enveloppe
*/
public Element createEnvelope(Document doc) {
Element html = doc.createElementNS(XHTML_NS, XHTML_PREFIX + ":html");
//set namespace attribute
html.setAttributeNS(SchemaFormBuilder.XMLNS_NAMESPACE_URI,
"xmlns:" + XHTML_PREFIX,
XHTMLWrapperElementsBuilder.XHTML_NS);
doc.appendChild(html);
//other namespaces
Enumeration enumeration = namespaces.keys();
while (enumeration.hasMoreElements()) {
String prefix = (String) enumeration.nextElement();
String ns = (String) namespaces.get(prefix);
html.setAttributeNS(SchemaFormBuilder.XMLNS_NAMESPACE_URI,
"xmlns:" + prefix,
ns);
}
return html;
}
/**
* create the element that will contain the content of the group (or repeat) element
*
* @param groupElement the group or repeat element
* @return the wrapper element
*/
public Element createGroupContentWrapper(Element groupElement) {
return groupElement;
}
/**
* create the wrapper element of the form
*
* @param enveloppeElement the form element (chiba:form or other)
* @return the wrapper element
*/
public Element createFormWrapper(Element enveloppeElement) {
Document doc = enveloppeElement.getOwnerDocument();
Element body = doc.createElementNS(XHTML_NS, XHTML_PREFIX + ":body");
//body.appendChild(formElement);
enveloppeElement.appendChild(body);
return body;
}
/**
* create the wrapper element of the xforms:model element
*
* @param modelElement the xforms:model element
* @return the wrapper element, already containing the model
*/
public Element createModelWrapper(Element modelElement) {
Document doc = modelElement.getOwnerDocument();
Element head = doc.createElementNS(XHTML_NS, XHTML_PREFIX + ":head");
head.appendChild(modelElement);
//eventually add other info
if ((title != null) && !title.equals("")) {
Element title_el = doc.createElementNS(XHTML_NS, XHTML_PREFIX + ":title");
Text title_text = doc.createTextNode(title);
title_el.appendChild(title_text);
head.appendChild(title_el);
}
if ((meta != null) && !meta.isEmpty()) {
Iterator it = meta.iterator();
while (it.hasNext()) {
String[] m = (String[]) it.next();
String http_equiv = m[0];
String name = m[1];
String content = m[2];
String scheme = m[3];
Element meta_el = doc.createElementNS(XHTML_NS, XHTML_PREFIX + ":META");
head.appendChild(meta_el);
//attributes
if ((http_equiv != null) && !http_equiv.equals("")) {
meta_el.setAttributeNS(XHTML_NS, XHTML_PREFIX + ":http-equiv", http_equiv);
}
if ((name != null) && !name.equals("")) {
meta_el.setAttributeNS(XHTML_NS, XHTML_PREFIX + ":name", name);
}
if ((content != null) && !content.equals("")) {
meta_el.setAttributeNS(XHTML_NS, XHTML_PREFIX + ":content", content);
}
if ((scheme != null) && !scheme.equals("")) {
meta_el.setAttributeNS(XHTML_NS, XHTML_PREFIX + ":scheme", scheme);
}
}
}
if ((links != null) && !links.isEmpty()) {
Iterator it = links.iterator();
while (it.hasNext()) {
String[] l = (String[]) it.next();
String href = l[0];
String type = l[1];
String rel = l[2];
Element link_el = doc.createElementNS(XHTML_NS, XHTML_PREFIX + ":LINK");
head.appendChild(link_el);
//attributes
if ((href != null) && !href.equals("")) {
link_el.setAttributeNS(XHTML_NS, XHTML_PREFIX + ":href", href);
}
if ((type != null) && !type.equals("")) {
link_el.setAttributeNS(XHTML_NS, XHTML_PREFIX + ":type", type);
}
if ((rel != null) && !rel.equals("")) {
link_el.setAttributeNS(XHTML_NS, XHTML_PREFIX + ":rel", rel);
}
}
}
return head;
}
}

View File

@@ -0,0 +1,472 @@
package org.alfresco.web.templating.xforms.servlet;
import org.alfresco.web.app.Application;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.httpclient.Cookie;
import org.chiba.adapter.ChibaAdapter;
import org.alfresco.web.templating.xforms.flux.FluxAdapter;
import org.chiba.tools.xslt.StylesheetLoader;
import org.chiba.tools.xslt.UIGenerator;
import org.chiba.tools.xslt.XSLTGenerator;
import org.chiba.xml.xforms.config.Config;
import org.chiba.xml.xforms.exception.XFormsException;
import org.chiba.xml.xforms.connector.http.AbstractHTTPConnector;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* The ChibaServlet handles all interactions between client and
* form-processor (ChibaBean) for the whole lifetime of a form-filling session.
* <br>
* The Processor will be started through a Get-request from the client
* pointing to the desired form-container. The Processor instance will
* be stored in a Session-object.<br>
* <br>
* All further interaction will be handled through Post-requests.
* Incoming request params will be mapped to data and action-handlers.
*
* @author Joern Turner
* @author Ulrich Nicolas Liss&eacute;
* @author William Boyd
* @version $Id: ChibaServlet.java,v 1.14 2005/12/21 22:59:27 unl Exp $
*/
public class ChibaServlet extends HttpServlet {
//init-params
private static Log logger = LogFactory.getLog(ChibaServlet.class);
private static final String FORM_PARAM_NAME = "form";
private static final String XSL_PARAM_NAME = "xslt";
private static final String CSS_PARAM_NAME = "css";
private static final String ACTIONURL_PARAM_NAME = "action_url";
public static final String CHIBA_ADAPTER = "chiba.adapter";
public static final String CHIBA_UI_GENERATOR = "chiba.ui.generator";
public static final String CHIBA_SUBMISSION_RESPONSE = "chiba.submission.response";
/*
* It is not thread safe to modify these variables once the
* init(ServletConfig) method has been called
*/
// the absolute path to the Chiba config-file
protected String configPath = null;
// the rootdir of this app; forms + documents fill be searched under this root
protected String contextRoot = null;
// where uploaded files are stored
protected String uploadDir = null;
protected String stylesPath = null;
protected String agent;
/**
* Returns a short description of the servlet.
*
* @return - Returns a short description of the servlet.
*/
public String getServletInfo() {
return "Servlet Controller for Chiba XForms Processor";
}
/**
* Destroys the servlet.
*/
public void destroy() {
}
/**
* Initializes the servlet.
*
* @param config - the ServletConfig object
* @throws javax.servlet.ServletException
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);
logger.info("--------------- initing ChibaServlet... ---------------");
//read some params from web-inf
contextRoot = getServletConfig().getServletContext().getRealPath("");
if (contextRoot == null)
contextRoot = getServletConfig().getServletContext().getRealPath(".");
//get the relative path to the chiba config-file
String path = getServletConfig().getInitParameter("chiba.config");
//get the real path for the config-file
if (path != null) {
configPath = getServletConfig().getServletContext().getRealPath(path);
}
//get the path for the stylesheets
path = getServletConfig().getServletContext().getInitParameter("chiba.xforms.stylesPath");
//get the real path for the stylesheets and configure a new StylesheetLoader with it
if (path != null) {
stylesPath = getServletConfig().getServletContext().getRealPath(path);
logger.info("stylesPath: " + stylesPath);
}
//uploadDir = contextRoot + "/" + getServletConfig().getServletContext().getInitParameter("chiba.upload");
uploadDir = getServletConfig().getServletContext().getInitParameter("chiba.upload");
//Security constraint
if (uploadDir != null) {
if (uploadDir.toUpperCase().indexOf("WEB-INF") >= 0) {
throw new ServletException("Chiba security constraint: uploadDir '" + uploadDir + "' not allowed");
}
}
//user-agent mappings
agent = getServletConfig().getServletContext().getInitParameter("chiba.useragent.ajax.path");
}
/**
* Starts a new form-editing session.<br>
* <p/>
* The default value of a number of settings can be overridden as follows:
* <p/>
* 1. The uru of the xform to be displayed can be specified by using a param name of 'form' and a param value
* of the location of the xform file as follows, which will attempt to load the current xforms file.
* <p/>
* http://localhost:8080/chiba-0.9.3/XFormsServlet?form=/forms/hello.xhtml
* <p/>
* 2. The uru of the CSS file used to style the form can be specified using a param name of 'css' as follows:
* <p/>
* http://localhost:8080/chiba-0.9.3/XFormsServlet?form=/forms/hello.xhtml&css=/chiba/my.css
* <p/>
* 3. The uri of the XSLT file used to generate the form can be specified using a param name of 'xslt' as follows:
* <p/>
* http://localhost:8080/chiba-0.9.3/XFormsServlet?form=/forms/hello.xhtml&xslt=/chiba/my.xslt
* <p/>
* 4. Besides these special params arbitrary other params can be passed via the GET-string and will be available
* in the context map of ChibaBean. This means they can be used as instance data (with the help of ContextResolver)
* or to set params for URI resolution.
*
* @param request servlet request
* @param response servlet response
* @throws javax.servlet.ServletException
* @throws java.io.IOException
* @see org.chiba.xml.xforms.connector.context.ContextResolver
* @see org.chiba.xml.xforms.connector.ConnectorFactory
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
ChibaAdapter adapter = null;
HttpSession session = request.getSession(true);
logger.info("--------------- new XForms session ---------------");
try {
//kill everything that may have lived before
session.removeAttribute(CHIBA_ADAPTER);
session.removeAttribute(CHIBA_UI_GENERATOR);
// determine Form to load
String formURI = /*getRequestURI(request) +*/ request.getParameter(FORM_PARAM_NAME);
logger.info("formURI: " + formURI);
String xslFile = request.getParameter(XSL_PARAM_NAME);
String css = request.getParameter(CSS_PARAM_NAME);
String actionURL = getActionURL(request, response,true);
logger.info("setting up adapeter");
//setup Adapter
adapter = setupAdapter(new FluxAdapter(session), session, formURI);
setContextParams(request, adapter);
storeCookies(request, adapter);
adapter.init();
if (load(adapter, response)) return;
if (replaceAll(adapter, response)) return;
response.setContentType("text/html");
PrintWriter out = response.getWriter();
logger.info("generating ui");
UIGenerator uiGenerator = createUIGenerator(request, actionURL, xslFile, css);
uiGenerator.setInputNode(adapter.getXForms());
uiGenerator.setOutput(out);
uiGenerator.generate();
//store adapter in session
session.setAttribute(CHIBA_ADAPTER, adapter);
session.setAttribute(CHIBA_UI_GENERATOR,uiGenerator);
out.close();
logger.info("done!");
} catch (Exception e) {
e.printStackTrace();
shutdown(adapter, session, e, response, request);
}
}
/**
* configures the an Adapter for interacting with the XForms processor (ChibaBean). The Adapter itself
* will create the XFormsProcessor (ChibaBean) and configure it for processing.
*
* If you'd like to use a different source of XForms documents e.g. DOM you should extend this class and
* overwrite this method. Please take care to also set the baseURI of the processor to a reasonable value
* cause this will be the fundament for all URI resolutions taking place.
*
* @param adapter the ChibaAdapter implementation to setup
* @param session - the Servlet session
* @param formPath - the relative location where forms are stored
* @return ServletAdapter
*/
protected ChibaAdapter setupAdapter(ChibaAdapter adapter,
HttpSession session,
String formPath)
throws XFormsException, URISyntaxException {
adapter.createXFormsProcessor();
if ((configPath != null) && !(configPath.equals(""))) {
adapter.setConfigPath(configPath);
}
adapter.setXForms(new URI(formPath));
adapter.setBaseURI(formPath);
adapter.setUploadDestination(uploadDir);
Map servletMap = new HashMap();
servletMap.put(ChibaAdapter.SESSION_ID, session.getId());
adapter.setContextParam(ChibaAdapter.SUBMISSION_RESPONSE, servletMap);
return adapter;
}
/**
* stores cookies that may exist in request and passes them on to processor for usage in
* HTTPConnectors. Instance loading and submission then uses these cookies. Important for
* applications using auth.
*
* @param request the servlet request
* @param adapter the Chiba adapter instance
*/
protected void storeCookies(HttpServletRequest request,ChibaAdapter adapter){
javax.servlet.http.Cookie[] cookiesIn = request.getCookies();
if (cookiesIn != null) {
Cookie[] commonsCookies = new org.apache.commons.httpclient.Cookie[cookiesIn.length];
for (int i = 0; i < cookiesIn.length; i += 1) {
javax.servlet.http.Cookie c = cookiesIn[i];
Cookie newCookie = new Cookie(c.getDomain(),
c.getName(),
c.getValue(),
c.getPath(),
c.getMaxAge(),
c.getSecure());
commonsCookies[i] = newCookie;
}
adapter.setContextParam(AbstractHTTPConnector.REQUEST_COOKIE,commonsCookies);
}
}
/**
*
* creates and configures the UI generating component.
* @param request
* @param actionURL
* @param xslFile
* @param css
* @return
* @throws XFormsException
*/
protected UIGenerator createUIGenerator(HttpServletRequest request,
String actionURL,
String xslFile,
String css)
throws XFormsException {
StylesheetLoader stylesheetLoader = new StylesheetLoader(stylesPath);
if (xslFile != null){
stylesheetLoader.setStylesheetFile(xslFile);
}
UIGenerator uiGenerator = new XSLTGenerator(stylesheetLoader);
//set parameters
uiGenerator.setParameter("contextroot",request.getContextPath());
uiGenerator.setParameter("action-url",actionURL);
uiGenerator.setParameter("debug-enabled", true /*String.valueOf(logger.isDebugEnabled()) */);
String selectorPrefix = Config.getInstance().getProperty(HttpRequestHandler.SELECTOR_PREFIX_PROPERTY,
HttpRequestHandler.SELECTOR_PREFIX_DEFAULT);
uiGenerator.setParameter("selector-prefix", selectorPrefix);
String removeUploadPrefix = Config.getInstance().getProperty(HttpRequestHandler.REMOVE_UPLOAD_PREFIX_PROPERTY,
HttpRequestHandler.REMOVE_UPLOAD_PREFIX_DEFAULT);
uiGenerator.setParameter("remove-upload-prefix", removeUploadPrefix);
if (css != null) {
uiGenerator.setParameter("css-file", css);
}
String dataPrefix = Config.getInstance().getProperty("chiba.web.dataPrefix");
uiGenerator.setParameter("data-prefix", dataPrefix);
String triggerPrefix = Config.getInstance().getProperty("chiba.web.triggerPrefix");
uiGenerator.setParameter("trigger-prefix", triggerPrefix);
uiGenerator.setParameter("user-agent", request.getHeader("User-Agent"));
uiGenerator.setParameter("scripted","true");
return uiGenerator;
}
/**
* this method is responsible for passing all context information needed by the Adapter and Processor from
* ServletRequest to ChibaContext. Will be called only once when the form-session is inited (GET).
*
* @param request the ServletRequest
* @param chibaAdapter the ChibaAdapter to use
*/
protected void setContextParams(HttpServletRequest request, ChibaAdapter chibaAdapter) {
//[1] pass user-agent to Adapter for UI-building
chibaAdapter.setContextParam(ServletAdapter.USERAGENT, request.getHeader("User-Agent"));
//[2] read any request params that are *not* Chiba params and pass them into the context map
Enumeration params = request.getParameterNames();
while (params.hasMoreElements()) {
String s = (String) params.nextElement();
//store all request-params we don't use in the context map of ChibaBean
if (!(s.equals(FORM_PARAM_NAME) ||
s.equals(XSL_PARAM_NAME) ||
s.equals(CSS_PARAM_NAME) ||
s.equals(ACTIONURL_PARAM_NAME))) {
String value = request.getParameter(s);
//servletAdapter.setContextProperty(s, value);
chibaAdapter.setContextParam(s, value);
if (logger.isDebugEnabled()) {
logger.debug("added request param '" + s + "' added to context");
}
}
}
}
/**
* @deprecated should be re-implemented using chiba events on adapter
*/
protected boolean load(ChibaAdapter adapter, HttpServletResponse response) throws XFormsException, IOException {
if (adapter.getContextParam(ChibaAdapter.LOAD_URI) != null) {
String redirectTo = (String) adapter.removeContextParam(ChibaAdapter.LOAD_URI);
adapter.shutdown();
response.sendRedirect(response.encodeRedirectURL(redirectTo));
return true;
}
return false;
}
/**
* @deprecated should be re-implemented using chiba events on adapter
*/
protected boolean replaceAll(ChibaAdapter chibaAdapter, HttpServletResponse response)
throws XFormsException, IOException {
if (chibaAdapter.getContextParam(ChibaAdapter.SUBMISSION_RESPONSE) != null) {
Map forwardMap = (Map) chibaAdapter.removeContextParam(ChibaAdapter.SUBMISSION_RESPONSE);
if (forwardMap.containsKey(ChibaAdapter.SUBMISSION_RESPONSE_STREAM)) {
forwardResponse(forwardMap, response);
chibaAdapter.shutdown();
return true;
}
}
return false;
}
private String getActionURL(HttpServletRequest request, HttpServletResponse response, boolean scripted) {
String defaultActionURL = getRequestURI(request) + agent;
String encodedDefaultActionURL = response.encodeURL(defaultActionURL);
int sessIdx = encodedDefaultActionURL.indexOf(";jsession");
String sessionId = null;
if (sessIdx > -1) {
sessionId = encodedDefaultActionURL.substring(sessIdx);
}
String actionURL = request.getParameter(ACTIONURL_PARAM_NAME);
if (null == actionURL) {
actionURL = encodedDefaultActionURL;
} else if (null != sessionId) {
actionURL += sessionId;
}
logger.info("actionURL: " + actionURL);
// encode the URL to allow for session id rewriting
return response.encodeURL(actionURL);
}
private String getRequestURI(HttpServletRequest request){
StringBuffer buffer = new StringBuffer(request.getScheme());
buffer.append("://");
buffer.append(request.getServerName());
buffer.append(":");
buffer.append(request.getServerPort()) ;
buffer.append(request.getContextPath());
return buffer.toString();
}
private void forwardResponse(Map forwardMap, HttpServletResponse response) throws IOException {
// fetch response stream
InputStream responseStream = (InputStream) forwardMap.remove(ChibaAdapter.SUBMISSION_RESPONSE_STREAM);
// copy header information
Iterator iterator = forwardMap.keySet().iterator();
while (iterator.hasNext()) {
String name = (String) iterator.next();
if ("Transfer-Encoding".equalsIgnoreCase(name)) {
// Some servers (e.g. WebSphere) may set a "Transfer-Encoding"
// with the value "chunked". This may confuse the client since
// ChibaServlet output is not encoded as "chunked", so this
// header is ignored.
continue;
}
String value = (String) forwardMap.get(name);
response.setHeader(name, value);
}
// copy stream content
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
for (int b = responseStream.read();
b > -1;
b = responseStream.read()) {
outputStream.write(b);
}
// close streams
responseStream.close();
outputStream.close();
}
protected void shutdown(ChibaAdapter chibaAdapter,
HttpSession session,
Exception e,
HttpServletResponse response,
HttpServletRequest request)
throws IOException,
ServletException {
// attempt to shutdown processor
if (chibaAdapter != null) {
try {
chibaAdapter.shutdown();
} catch (XFormsException xfe) {
xfe.printStackTrace();
}
}
Application.handleServletError(this.getServletContext(),
request,
response,
e,
logger,
null);
}
}
// end of class

View File

@@ -0,0 +1,101 @@
package org.alfresco.web.templating.xforms.servlet;
import org.apache.commons.fileupload.FileUpload;
import org.apache.log4j.Category;
import org.chiba.adapter.ChibaAdapter;
import org.chiba.adapter.ChibaEvent;
import org.chiba.adapter.DefaultChibaEventImpl;
import org.chiba.xml.xforms.config.Config;
import org.chiba.tools.xslt.UIGenerator;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Provides extra functionality that's not easily handled with AJAX. This helper servlet will only be triggered in
* in one of two situations:<br>
* 1. an upload<br>
* for an file upload to happen the browser has to submit the file as multipart-request. In this case the browser
* form must be submitted cause there's no way to get the file content from javascript to send an AJAX request.<br><br>
* 2. for a submission replace="all"<br>
* This mode requires that the response will be directly streamed back to the client, replacing the existing viewport.
* To maintain the correct location of that response in the location bar of the browser there seems no way but to
* also let the browser do the request/response handling itself by the use of a normal form submit.
*
* @author Joern Turner
* @version $Version: $
*/
public class FluxHelperServlet extends ChibaServlet {
//init-params
private static Category cat = Category.getInstance(FluxHelperServlet.class);
/**
* Returns a short description of the servlet.
*
* @return - Returns a short description of the servlet.
*/
public String getServletInfo() {
return "Ajax Servlet Controller for Chiba XForms Processor";
}
/**
* Destroys the servlet.
*/
public void destroy() {
}
/**
* handles all interaction with the user during a form-session.
*
* Note: this method is only triggered if the
* browser has javascript turned off.
*
* @param request servlet request
* @param response servlet response
* @throws javax.servlet.ServletException
* @throws java.io.IOException
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession(true);
ChibaAdapter chibaAdapter =null;
response.setContentType("text/html");
try {
chibaAdapter = (ChibaAdapter) session.getAttribute(CHIBA_ADAPTER);
if (chibaAdapter == null) {
throw new ServletException(Config.getInstance().getErrorMessage("session-invalid"));
}
ChibaEvent chibaEvent = new DefaultChibaEventImpl();
chibaEvent.initEvent("http-request",null,request);
chibaAdapter.dispatch(chibaEvent);
boolean isUpload = FileUpload.isMultipartContent(request);
if(isUpload){
ServletOutputStream out = response.getOutputStream();
out.println("<html><head><title>status</title></head><body><div id='upload-status-ok' style='width:10px;height:10px;background:green'>&nbsp;</div></body></html>");
out.close();
}else{
if(!replaceAll(chibaAdapter, response)){
UIGenerator uiGenerator = (UIGenerator) session.getAttribute(CHIBA_UI_GENERATOR);
uiGenerator.setInputNode(chibaAdapter.getXForms());
uiGenerator.setOutput(response.getWriter());
uiGenerator.generate();
response.getWriter().close();
}
}
} catch (Exception e) {
shutdown(chibaAdapter, session, e, response, request);
}
}
}
// end of class

View File

@@ -0,0 +1,439 @@
package org.alfresco.web.templating.xforms.servlet;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.log4j.Category;
import org.chiba.xml.xforms.ChibaBean;
import org.chiba.xml.xforms.config.Config;
import org.chiba.xml.xforms.events.XFormsEventFactory;
import org.chiba.xml.xforms.exception.XFormsException;
import org.chiba.xml.xforms.ui.Repeat;
import org.chiba.adapter.ChibaEvent;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.*;
/**
* Default implementation for handling http servlet requests.
*
* @author joern turner
* @version $Id: HttpRequestHandler.java,v 1.7 2005/10/27 23:10:31 joernt Exp $
*/
public class HttpRequestHandler {
private static final Category LOGGER = Category.getInstance(HttpRequestHandler.class);
public static final String DATA_PREFIX_PROPERTY = "chiba.web.dataPrefix";
public static final String TRIGGER_PREFIX_PROPERTY = "chiba.web.triggerPrefix";
public static final String SELECTOR_PREFIX_PROPERTY = "chiba.web.selectorPrefix";
public static final String REMOVE_UPLOAD_PREFIX_PROPERTY = "chiba.web.removeUploadPrefix";
public static final String DATA_PREFIX_DEFAULT = "d_";
public static final String TRIGGER_PREFIX_DEFAULT = "t_";
public static final String SELECTOR_PREFIX_DEFAULT = "s_";
public static final String REMOVE_UPLOAD_PREFIX_DEFAULT = "ru_";
private ChibaBean chibaBean;
private String dataPrefix;
private String selectorPrefix;
private String triggerPrefix;
private String removeUploadPrefix;
private String uploadRoot;
public HttpRequestHandler(ChibaBean chibaBean) {
this.chibaBean = chibaBean;
}
/**
* executes this handler.
*
* @throws XFormsException
*/
public void execute(ChibaEvent event) throws XFormsException {
//HttpServletRequest request = (HttpServletRequest) this.chibaBean.getContext().get(ServletAdapter.HTTP_SERVLET_REQUEST);
HttpServletRequest request= (HttpServletRequest) event.getContextInfo();
String contextRoot = request.getSession().getServletContext().getRealPath("");
if (contextRoot == null) {
contextRoot = request.getSession().getServletContext().getRealPath(".");
}
String uploadDir = (String) this.chibaBean.getContext().get(ServletAdapter.HTTP_UPLOAD_DIR);
this.uploadRoot = new File(contextRoot, uploadDir).getAbsolutePath();
handleRequest(request);
}
/**
* checks whether we have multipart or urlencoded request and processes it accordingly. After updating
* the data, a reacalculate, revalidate refresh sequence is fired and the found trigger is executed.
*
* @param request Servlet request
* @throws org.chiba.xml.xforms.exception.XFormsException
* todo: implement action block behaviour
*/
protected void handleRequest(HttpServletRequest request) throws XFormsException {
String trigger = null;
// Check that we have a file upload request
boolean isMultipart = FileUpload.isMultipartContent(request);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("request isMultipart: " + isMultipart);
LOGGER.debug("base URI: " + this.chibaBean.getBaseURI());
LOGGER.debug("user agent: " + request.getHeader("User-Agent"));
}
if (isMultipart) {
trigger = processMultiPartRequest(request, trigger);
} else {
trigger = processUrlencodedRequest(request, trigger);
}
// finally activate trigger if any
if (trigger != null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("trigger '" + trigger + "'");
}
this.chibaBean.dispatch(trigger, XFormsEventFactory.DOM_ACTIVATE);
}
}
/**
* @param request Servlet request
* @param trigger Trigger control
* @return the calculated trigger
* @throws XFormsException If an error occurs
*/
protected String processMultiPartRequest(HttpServletRequest request, String trigger) throws XFormsException {
DiskFileUpload upload = new DiskFileUpload();
String encoding = request.getCharacterEncoding();
if (encoding == null) {
encoding = "ISO-8859-1";
}
upload.setRepositoryPath(this.uploadRoot);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("root dir for uploads: " + this.uploadRoot);
}
List items;
try {
items = upload.parseRequest(request);
} catch (FileUploadException fue) {
throw new XFormsException(fue);
}
Map formFields = new HashMap();
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
String itemName = item.getName();
String fieldName = item.getFieldName();
String id = fieldName.substring(Config.getInstance().getProperty("chiba.web.dataPrefix").length());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Multipart item name is: " + itemName
+ " and fieldname is: " + fieldName
+ " and id is: " + id);
LOGGER.debug("Is formfield: " + item.isFormField());
}
if (item.isFormField()) {
// check for upload-remove action
if (fieldName.startsWith(getRemoveUploadPrefix())) {
id = fieldName.substring(getRemoveUploadPrefix().length());
// if data is null, file will be removed ...
// TODO: remove the file from the disk as well
chibaBean.updateControlValue(id, "", "", null);
continue;
}
// It's a field name, it means that we got a non-file
// form field. Upload is not required. We must treat it as we
// do in processUrlencodedRequest()
processMultipartParam(formFields, fieldName, item, encoding);
} else {
String uniqueFilename = new File(getUniqueParameterName("file"),
new File(itemName).getName()).getPath();
File savedFile = new File(this.uploadRoot, uniqueFilename);
byte[] data = null;
data = processMultiPartFile(item, id, savedFile, encoding, data);
// if data is null, file will be removed ...
// TODO: remove the file from the disk as well
chibaBean.updateControlValue(id, item.getContentType(),
itemName, data);
}
// handle regular fields
if (formFields.size() > 0) {
Iterator it = formFields.keySet().iterator();
while (it.hasNext()) {
fieldName = (String) it.next();
String[] values = (String[]) formFields.get(fieldName);
// [1] handle data
handleData(fieldName, values);
// [2] handle selector
handleSelector(fieldName, values[0]);
// [3] handle trigger
trigger = handleTrigger(trigger, fieldName);
}
}
}
return trigger;
}
protected String processUrlencodedRequest(HttpServletRequest request, String trigger) throws XFormsException {
// iterate request parameters
Enumeration names = request.getParameterNames();
while (names.hasMoreElements()) {
String paramName = names.nextElement().toString();
String[] values = request.getParameterValues(paramName);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(this + " parameter-name: " + paramName);
for (int i = 0; i < values.length; i++) {
LOGGER.debug(this + " value: " + values[i]);
}
}
// [1] handle data
handleData(paramName, values);
// [2] handle selector
handleSelector(paramName, values[0]);
// [3] handle trigger
trigger = handleTrigger(trigger, paramName);
}
return trigger;
}
/**
* @param name
* @throws XFormsException
*/
protected void handleData(String name, String[] values)
throws XFormsException {
if (name.startsWith(getDataPrefix())) {
String id = name.substring(getDataPrefix().length());
// assemble new control value
String newValue;
if (values.length > 1) {
StringBuffer buffer = new StringBuffer(values[0]);
for (int i = 1; i < values.length; i++) {
buffer.append(" ").append(values[i]);
}
newValue = trim( buffer.toString() );
} else {
newValue = trim( values[0] );
}
this.chibaBean.updateControlValue(id, newValue);
}
}
/**
* patch to handle linefeed duplication in textareas with some browsers.
*
* @param value the value where linebreaks will be trimmed
* @return returns a cleaned up version of the value
*/
protected String trim(String value) {
if (value != null && value.length() > 0) {
value = value.replaceAll("\r\n", "\r");
value = value.trim();
}
return value;
}
/**
* @param name
* @throws XFormsException
*/
protected void handleSelector(String name, String value) throws XFormsException {
if (name.startsWith(getSelectorPrefix())) {
int separator = value.lastIndexOf(':');
String id = value.substring(0, separator);
int index = Integer.valueOf(value.substring(separator + 1)).intValue();
Repeat repeat = (Repeat) this.chibaBean.lookup(id);
repeat.setIndex(index);
}
}
protected String handleTrigger(String trigger, String name) {
if ((trigger == null) && name.startsWith(getTriggerPrefix())) {
String parameter = name;
int x = parameter.lastIndexOf(".x");
int y = parameter.lastIndexOf(".y");
if (x > -1) {
parameter = parameter.substring(0, x);
}
if (y > -1) {
parameter = parameter.substring(0, y);
}
// keep trigger id
trigger = name.substring(getTriggerPrefix().length());
}
return trigger;
}
private byte[] processMultiPartFile(FileItem item, String id, File savedFile, String encoding, byte[] data)
throws XFormsException {
// some data uploaded ...
if (item.getSize() > 0) {
if (chibaBean.storesExternalData(id)) {
// store data to file and create URI
try {
savedFile.getParentFile().mkdir();
item.write(savedFile);
} catch (Exception e) {
throw new XFormsException(e);
}
// content is URI in this case
try {
data = savedFile.toURI().toString().getBytes(encoding);
} catch (UnsupportedEncodingException e) {
throw new XFormsException(e);
}
} else {
// content is the data
data = item.get();
}
}
return data;
}
private void processMultipartParam(Map formFields, String fieldName, FileItem item, String encoding) throws XFormsException {
String values[] = (String[]) formFields.get(fieldName);
String formFieldValue = null;
try {
formFieldValue = item.getString(encoding);
} catch (UnsupportedEncodingException e) {
throw new XFormsException(e.getMessage(), e);
}
if (values == null) {
formFields.put(fieldName, new String[]{formFieldValue});
} else {
// not very effective, but not many duplicate values
// expected either ...
String[] tmp = new String[values.length + 1];
System.arraycopy(values, 0, tmp, 0, values.length);
tmp[values.length] = formFieldValue;
formFields.put(fieldName, tmp);
}
}
/**
* returns the prefix which is used to identify trigger parameters.
*
* @return the prefix which is used to identify trigger parameters
*/
protected final String getTriggerPrefix() {
if (this.triggerPrefix == null) {
try {
this.triggerPrefix =
Config.getInstance().getProperty(TRIGGER_PREFIX_PROPERTY, TRIGGER_PREFIX_DEFAULT);
} catch (Exception e) {
this.triggerPrefix = TRIGGER_PREFIX_DEFAULT;
}
}
return this.triggerPrefix;
}
protected final String getDataPrefix() {
if (this.dataPrefix == null) {
try {
this.dataPrefix = Config.getInstance().getProperty(DATA_PREFIX_PROPERTY, DATA_PREFIX_DEFAULT);
} catch (Exception e) {
this.dataPrefix = DATA_PREFIX_DEFAULT;
}
}
return this.dataPrefix;
}
protected final String getRemoveUploadPrefix() {
if (this.removeUploadPrefix == null) {
try {
this.removeUploadPrefix = Config.getInstance().getProperty(REMOVE_UPLOAD_PREFIX_PROPERTY, REMOVE_UPLOAD_PREFIX_DEFAULT);
} catch (Exception e) {
this.removeUploadPrefix = REMOVE_UPLOAD_PREFIX_DEFAULT;
}
}
return this.removeUploadPrefix;
}
private String getUniqueParameterName(String prefix) {
return prefix + Integer.toHexString((int) (Math.random() * 10000));
}
/**
* returns the configured prefix which identifies 'selector' parameters. These are used to transport
* the state of repeat indices via http.
*
* @return the prefix for selector parameters from the configuration
*/
public final String getSelectorPrefix() {
if (this.selectorPrefix == null) {
try {
this.selectorPrefix =
Config.getInstance().getProperty(SELECTOR_PREFIX_PROPERTY,
SELECTOR_PREFIX_DEFAULT);
} catch (Exception e) {
this.selectorPrefix = SELECTOR_PREFIX_DEFAULT;
}
}
return this.selectorPrefix;
}
/**
* Get the value of chibaBean.
*
* @return the value of chibaBean
*/
public ChibaBean getChibaBean() {
return this.chibaBean;
}
}
// end of class

View File

@@ -0,0 +1,167 @@
package org.alfresco.web.templating.xforms.servlet;
import org.apache.log4j.Category;
import org.chiba.adapter.AbstractChibaAdapter;
import org.chiba.adapter.ChibaEvent;
import org.chiba.xml.xforms.events.XFormsEvent;
import org.chiba.xml.xforms.events.XFormsEventFactory;
import org.chiba.xml.xforms.exception.XFormsException;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import java.util.Map;
/**
* integrates XForms Processor into Web-applications and handles request
* processing. This is the default implementation of ChibaAdapter and besides
* handling the interaction it also manages a UIGenerator to build the rendered
* output for the browser.
*
* @author joern turner
* @version $Id: ServletAdapter.java,v 1.8 2005/12/15 11:45:38 unl Exp $
*/
public class ServletAdapter extends AbstractChibaAdapter implements EventListener {
private static final Category LOGGER = Category.getInstance(ServletAdapter.class);
public static final String HTTP_SERVLET_REQUEST = "chiba.web.request";
//public static final String HTTP_SESSION_OBJECT = "chiba.web.session";
public static final String HTTP_UPLOAD_DIR = "chiba.web.uploadDir";
//private ChibaBean chibaBean = null;
//private String formURI = null;
//private String actionUrl = null;
//private String CSSFile = null;
//private String stylesheet = null;
//private UIGenerator generator = null;
//private String stylesheetPath = null;
//private HashMap context = null;
public static final String USERAGENT = "chiba.useragent";
private HttpRequestHandler handler;
public static final Object XSLT_PATH = "xslt-path";
/**
* Creates a new ServletAdapter object.
*/
public ServletAdapter() {
}
/**
* place to put application-specific params or configurations before
* actually starting off the XFormsProcessor. It's the responsibility of
* this method to call chibaBean.init() to finish up the processor setup.
*
* @throws XFormsException If an error occurs
*/
public void init() throws XFormsException {
this.chibaBean.init();
this.handler = getNewInteractionHandler();
}
/**
* ServletAdapter knows and executes only one ChibaEvent: 'http-request'
* which will contain the HttpServletRequest as contextInfo.
*
* @param event only events of type 'http-request' will be handled
* @throws XFormsException
*/
public void dispatch(ChibaEvent event) throws XFormsException {
if (event.getEventName().equals("http-request")) {
this.handler.execute(event);
}
else {
LOGGER.warn("unknown event: '" + event.getEventName() + "' - ignoring");
}
}
/**
* terminates the XForms processing. right place to do cleanup of
* resources.
*
* @throws org.chiba.xml.xforms.exception.XFormsException
*/
public void shutdown() throws XFormsException {
this.chibaBean.shutdown();
}
/**
* Instructs the application environment to forward the given response.
*
* @param response a map containing at least a response stream and optional
* header information.
*/
public void forward(Map response) {
this.chibaBean.getContext().put(SUBMISSION_RESPONSE, response);
}
// todo: should be set by servlet
/**
* return a new InteractionHandler.
* <p/>
* This method returns a new HttpRequestHandler.
*
* @return returns a new
*/
protected HttpRequestHandler getNewInteractionHandler()
throws XFormsException {
return new HttpRequestHandler(this.chibaBean);
}
public void setUploadDestination(String uploadDir) {
super.setUploadDestination(uploadDir);
//HttpRequestHandler uses this
// todo: should be a member of request handler and set directly
setContextParam(HTTP_UPLOAD_DIR, uploadDir);
}
// event handling
// todo: should be moved up to base class
/**
* This method is called whenever an event occurs of the type for which the
* <code> EventListener</code> interface was registered.
*
* @param event The <code>Event</code> contains contextual information about
* the event. It also contains the <code>stopPropagation</code> and
* <code>preventDefault</code> methods which are used in determining the
* event's flow and default action.
*/
public void handleEvent(Event event) {
String type = event.getType();
String targetId = ((Element) event.getTarget()).getAttributeNS(null, "id");
XFormsEvent xformsEvent = (XFormsEvent) event;
if (XFormsEventFactory.CHIBA_LOAD_URI.equals(type)) {
handleLoadURI(targetId, (String) xformsEvent.getContextInfo("uri"), (String) xformsEvent.getContextInfo("show"));
return;
}
if (XFormsEventFactory.CHIBA_RENDER_MESSAGE.equals(type)) {
handleMessage(targetId, (String) xformsEvent.getContextInfo("message"), (String) xformsEvent.getContextInfo("level"));
return;
}
if (XFormsEventFactory.CHIBA_REPLACE_ALL.equals(type)) {
handleReplaceAll(targetId, (Map) xformsEvent.getContextInfo("header"), xformsEvent.getContextInfo("body"));
return;
}
// unknown event ignored
}
// todo: *either* move up these three methods as abstract template methods *or* use event log ?
public void handleLoadURI(String targetId, String uri, String show) {
// todo
}
public void handleMessage(String targetId, String message, String level) {
// todo
}
public void handleReplaceAll(String targetId, Map header, Object body) {
// todo
}
}
// end of class

View File

@@ -0,0 +1,84 @@
package org.alfresco.web.templating.xforms.servlet;
import org.chiba.adapter.ChibaAdapter;
import org.chiba.xml.xforms.exception.XFormsException;
import org.apache.log4j.Category;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Map;
/**
* Returns a submission response exactly once.
*
* @author Ulrich Nicolas Liss&eacute;
* @version $Id: SubmissionResponseServlet.java,v 1.1 2005/12/21 22:59:27 unl Exp $
*/
public class SubmissionResponseServlet extends HttpServlet {
private static Category LOGGER = Category.getInstance(SubmissionResponseServlet.class);
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
// lookup session
HttpSession session = request.getSession(false);
if (session != null) {
// lookup attribute containing submission response map
Map submissionResponse = (Map) session.getAttribute(ChibaServlet.CHIBA_SUBMISSION_RESPONSE);
if (submissionResponse != null) {
// shutdown form session
ChibaAdapter adapter = (ChibaAdapter) session.getAttribute(ChibaServlet.CHIBA_ADAPTER);
if (adapter != null) {
try {
adapter.shutdown();
}
catch (XFormsException e) {
LOGGER.error("xforms shutdown failed", e);
}
}
// remove session attributes
session.removeAttribute(ChibaServlet.CHIBA_ADAPTER);
session.removeAttribute(ChibaServlet.CHIBA_SUBMISSION_RESPONSE);
// copy header fields
Map headerMap = (Map) submissionResponse.get("header");
Iterator iterator = headerMap.keySet().iterator();
while (iterator.hasNext()) {
final String name = (String) iterator.next();
if (name.equalsIgnoreCase("Transfer-Encoding")) {
// Some servers (e.g. WebSphere) may set a "Transfer-Encoding"
// with the value "chunked". This may confuse the client since
// ChibaServlet output is not encoded as "chunked", so this
// header is ignored.
continue;
}
final String value = (String) headerMap.get(name);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("added header: " + name + "=" + value);
}
response.setHeader(name, value);
}
// copy body stream
InputStream bodyStream = (InputStream) submissionResponse.get("body");
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
for (int b = bodyStream.read(); b > -1; b = bodyStream.read()) {
outputStream.write(b);
}
// close streams
bodyStream.close();
outputStream.close();
}
}
// response.sendError(HttpServletResponse.SC_FORBIDDEN, "no submission response available");
}
}

View File

@@ -0,0 +1,5 @@
# Tokens
chiba-version=1.0.0
baseurl.host=localhost
baseurl.port=8080

View File

@@ -0,0 +1 @@
@version.major@ [build @version.build@]