[Yanel-commits] rev 25627 - in
public/yanel/trunk/src/impl/java/org/wyona/yanel/impl: .
resources resources/usecase
josias at wyona.com
josias at wyona.com
Fri Jun 29 16:52:32 CEST 2007
Author: josias
Date: 2007-06-29 16:52:32 +0200 (Fri, 29 Jun 2007)
New Revision: 25627
Added:
public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/
public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/
public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/Executable.java
public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/ExecutableUsecaseResource.java
public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseException.java
public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseResource.java
public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseView.java
Log:
added core classes of usecase framework
Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/Executable.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/Executable.java (rev 0)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/Executable.java 2007-06-29 14:52:32 UTC (rev 25627)
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.wyona.org/licenses/APACHE-LICENSE-2.0
+ *
+ * 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.wyona.yanel.impl.resources.usecase;
+
+
+/**
+ *
+ */
+public interface Executable {
+
+ boolean checkPreconditions() throws UsecaseException;
+ void execute() throws UsecaseException;
+ void cancel() throws UsecaseException;
+ boolean hasErrors();
+ String getErrorMessages();
+}
Property changes on: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/Executable.java
___________________________________________________________________
Name: svn:eol-style
+ native
Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/ExecutableUsecaseResource.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/ExecutableUsecaseResource.java (rev 0)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/ExecutableUsecaseResource.java 2007-06-29 14:52:32 UTC (rev 25627)
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.wyona.org/licenses/APACHE-LICENSE-2.0
+ *
+ * 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.wyona.yanel.impl.resources.usecase;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.log4j.Category;
+
+/**
+ * The standard executable usecase works as follows:
+ * - display the "default" view
+ * this view has a form with a submit button and a cancel button.
+ * - if the user clicks submit, the checkPreconditions() method is executed.
+ * - if there are any errors, the "default" view is displayed again,
+ * showing the error messages.
+ * - if everything is ok, the execute() method is called
+ * - display the "done" view
+ * - if the user cancels, call the cancel() method and then show the "cancel" view.
+ */
+public class ExecutableUsecaseResource extends UsecaseResource implements Executable {
+
+ private static Category log = Category.getInstance(ExecutableUsecaseResource.class);
+
+ protected static final String VIEW_DONE = "done";
+ protected static final String VIEW_CANCEL = "cancel";
+
+ protected static final String PARAM_SUBMIT = "submit";
+ protected static final String PARAM_CANCEL = "cancel";
+
+ protected List infoMessages;
+ protected List errorMessages;
+
+ /**
+ *
+ */
+ public ExecutableUsecaseResource() {
+ this.infoMessages = new LinkedList();
+ this.errorMessages = new LinkedList();
+ }
+
+ protected UsecaseView processUsecase(String viewID) throws UsecaseException {
+ if (getParameter(PARAM_SUBMIT) != null) {
+ if (!checkPreconditions() || hasErrors()) {
+ return generateView(VIEW_DEFAULT);
+ }
+ execute();
+ return generateView(VIEW_DONE);
+ } else if (getParameter(PARAM_CANCEL) != null) {
+ cancel();
+ return generateView(VIEW_CANCEL);
+ } else {
+ return generateView(VIEW_DEFAULT); // TODO: should consider viewID?
+ }
+ }
+
+ public void cancel() throws UsecaseException {
+ // implement in subclass
+ }
+
+ public boolean checkPreconditions() throws UsecaseException {
+ // implement in subclass
+ return true;
+ }
+
+ public void execute() throws UsecaseException {
+ // implement in subclass
+ }
+
+ public boolean hasErrors() {
+ return this.errorMessages.size() > 0;
+ }
+
+ public String getErrorMessages() {
+ Iterator iter = this.errorMessages.iterator();
+ StringBuffer buf = new StringBuffer();
+ while (iter.hasNext()) {
+ String msg = (String)iter.next();
+ buf.append(msg);
+ }
+ return buf.toString();
+ }
+
+ public void addError(String error) {
+ this.errorMessages.add(error);
+ }
+
+ public boolean hasInfoMessages() {
+ return this.infoMessages.size() > 0;
+ }
+
+ public String getInfoMessages() {
+ Iterator iter = this.infoMessages.iterator();
+ StringBuffer buf = new StringBuffer();
+ while (iter.hasNext()) {
+ String msg = (String)iter.next();
+ buf.append(msg);
+ }
+ return buf.toString();
+ }
+
+ public void addInfoMessage(String msg) {
+ this.infoMessages.add(msg);
+ }
+
+}
Property changes on: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/ExecutableUsecaseResource.java
___________________________________________________________________
Name: svn:eol-style
+ native
Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseException.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseException.java (rev 0)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseException.java 2007-06-29 14:52:32 UTC (rev 25627)
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.wyona.org/licenses/APACHE-LICENSE-2.0
+ *
+ * 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.wyona.yanel.impl.resources.usecase;
+
+public class UsecaseException extends Exception {
+
+ /**
+ *
+ */
+ public UsecaseException() {
+ super();
+ }
+
+ /**
+ *
+ */
+ public UsecaseException(Throwable t) {
+ super(t);
+ }
+
+ /**
+ *
+ */
+ public UsecaseException(String s) {
+ super(s);
+ }
+
+ /**
+ *
+ */
+ public UsecaseException(String s, Throwable t) {
+ super(s, t);
+ }
+
+}
Property changes on: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseException.java
___________________________________________________________________
Name: svn:eol-style
+ native
Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseResource.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseResource.java (rev 0)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseResource.java 2007-06-29 14:52:32 UTC (rev 25627)
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.wyona.org/licenses/APACHE-LICENSE-2.0
+ *
+ * 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.wyona.yanel.impl.resources.usecase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.configuration.ConfigurationUtil;
+import org.apache.commons.jelly.JellyContext;
+import org.apache.commons.jelly.XMLOutput;
+import org.apache.log4j.Category;
+import org.apache.xml.resolver.tools.CatalogResolver;
+import org.apache.xml.serializer.Serializer;
+import org.w3c.dom.Document;
+import org.wyona.yanel.core.Resource;
+import org.wyona.yanel.core.ResourceConfiguration;
+import org.wyona.yanel.core.api.attributes.ViewableV2;
+import org.wyona.yanel.core.attributes.viewable.View;
+import org.wyona.yanel.core.attributes.viewable.ViewDescriptor;
+import org.wyona.yanel.core.serialization.SerializerFactory;
+import org.wyona.yanel.core.transformation.I18nTransformer2;
+import org.wyona.yanel.core.util.PathUtil;
+import org.wyona.yarep.core.Repository;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ *
+ */
+public class UsecaseResource extends Resource implements ViewableV2 {
+
+ private static Category log = Category.getInstance(UsecaseResource.class);
+
+ protected static final String VIEW_DEFAULT = "default";
+
+ protected HashMap views;
+
+ /**
+ *
+ */
+ public UsecaseResource() {
+ }
+
+ public View getView(String viewID) throws Exception {
+ init();
+ return processUsecase(viewID);
+ }
+
+ protected void init() throws UsecaseException {
+ // reads views from configuration:
+ try {
+ this.views = new HashMap();
+ Document customConfigDoc = getConfiguration().getCustomConfiguration();
+ if (customConfigDoc != null) {
+ Configuration config = ConfigurationUtil.toConfiguration(customConfigDoc.getDocumentElement());
+ Configuration viewsConfig = config.getChild("views");
+ Configuration[] viewConfigs = viewsConfig.getChildren("view");
+ for (int i = 0; i < viewConfigs.length; i++) {
+ String id = viewConfigs[i].getAttribute("id");
+ String type = viewConfigs[i].getAttribute("type");
+ UsecaseView view = new UsecaseView(id, type);
+ view.configure(viewConfigs[i]);
+ this.views.put(id, view);
+ }
+ }
+ } catch (ConfigurationException e) {
+ String errorMsg = "Error configuring usecase: " + getName() + ": " + e.toString();
+ log.error(errorMsg, e);
+ throw new UsecaseException(errorMsg, e);
+ }
+ }
+
+ protected UsecaseView processUsecase(String viewID) throws UsecaseException {
+ return generateView(viewID);
+ }
+
+ protected UsecaseView generateView(String viewID) throws UsecaseException {
+ if (viewID == null || viewID.length() == 0) {
+ viewID = VIEW_DEFAULT;
+ }
+ UsecaseView view = (UsecaseView)this.views.get(viewID);
+
+ if (view == null) {
+ throw new UsecaseException("Usecase " + getName() + " has no view with id: " + viewID);
+ }
+
+ if (view.getType().equals(UsecaseView.TYPE_JELLY)) {
+ String viewTemplate = view.getTemplate();
+ renderJellyView(view, viewTemplate);
+ return view;
+ } else if (view.getType().equals(UsecaseView.TYPE_REDIRECT)) {
+ String redirectURL = getRedirectURL(view);
+ view.setRedirectURL(redirectURL);
+ return view;
+ } else if (view.getType().equals(UsecaseView.TYPE_CUSTOM)) {
+ renderCustomView(view);
+ return view;
+ } else {
+ throw new UsecaseException("Usecase " + getName() + " has invalid view type: " + view.getType());
+ }
+ }
+
+ protected String getName() {
+ return "name";
+ }
+
+ protected void renderJellyView(UsecaseView view, String viewTemplate) throws UsecaseException {
+ try {
+ Repository repo = this.getRealm().getRepository();
+
+ JellyContext jellyContext = new JellyContext();
+ jellyContext.setVariable("resource", this);
+ //jellyContext.setVariable("request", request);
+
+ // at first we write the jelly output to a stream,
+ // instead of feeding it directly to the sax pipeline,
+ // because otherwise there is an error: EmptyStackException
+ ByteArrayOutputStream jellyResultStream = new ByteArrayOutputStream();
+ XMLOutput jellyOutput = XMLOutput.createXMLOutput(jellyResultStream);
+
+ //String viewTemplate = view.getTemplate();
+ jellyContext.runScript(new InputSource(repo.getNode(viewTemplate).getInputStream()), jellyOutput);
+ jellyOutput.flush();
+
+ // create reader:
+ XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+ CatalogResolver catalogResolver = new CatalogResolver();
+ xmlReader.setEntityResolver(catalogResolver);
+
+ // create xslt transformer:
+ SAXTransformerFactory tf = (SAXTransformerFactory)TransformerFactory.newInstance();
+
+ String[] xsltPath = getResourceConfigProperties("xslt");
+
+ TransformerHandler[] xsltHandlers = new TransformerHandler[xsltPath.length];
+ for (int i = 0; i < xsltPath.length; i++) {
+ xsltHandlers[i] = tf.newTransformerHandler(new StreamSource(repo.getNode(xsltPath[i]).getInputStream()));
+ xsltHandlers[i].getTransformer().setParameter("yanel.path.name", PathUtil.getName(getPath()));
+ xsltHandlers[i].getTransformer().setParameter("yanel.path", getPath());
+ xsltHandlers[i].getTransformer().setParameter("yanel.back2context", PathUtil.backToContext(realm, getPath()));
+ xsltHandlers[i].getTransformer().setParameter("yanel.back2realm", PathUtil.backToRealm(getPath()));
+ xsltHandlers[i].getTransformer().setParameter("language", getRequestedLanguage());
+ xsltHandlers[i].getTransformer().setParameter("yanel.reservedPrefix", "yanel"); // TODO don't hardcode
+ }
+
+ // create i18n transformer:
+ //I18nTransformer2 i18nTransformer = new I18nTransformer2("global", getRequestedLanguage(), getRealm().getDefaultLanguage());
+ //i18nTransformer.setEntityResolver(catalogResolver);
+
+ Serializer serializer = SerializerFactory.getSerializer(SerializerFactory.XHTML_STRICT);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutputStream(baos);
+
+ //XMLOutput jellyOutput = new XMLOutput(xsltHandlers[0]);
+ xmlReader.setContentHandler(xsltHandlers[0]);
+ for (int i = 0; i < xsltHandlers.length - 1; i++) {
+ xsltHandlers[i].setResult(new SAXResult(xsltHandlers[i+1]));
+ }
+ xsltHandlers[xsltHandlers.length - 1].setResult(new SAXResult(serializer.asContentHandler()));
+ //XMLOutput jellyOutput = new XMLOutput(serializer.asContentHandler());
+ //FileOutputStream os = new FileOutputStream("/home/josias/tmp/test2.xml");
+
+ // execute pipeline:
+ xmlReader.parse(new InputSource(new ByteArrayInputStream(jellyResultStream.toByteArray())));
+
+ view.setInputStream(new ByteArrayInputStream(baos.toByteArray()));
+ view.setMimeType("application/xhtml+xml");
+ } catch (Exception e) {
+ String errorMsg = "Error creating jelly view of usecase: " + getName() + ": " + e;
+ log.error(errorMsg, e);
+ throw new UsecaseException(errorMsg, e);
+ }
+ }
+
+ protected String getRedirectURL(UsecaseView view) {
+ return view.getRedirectURL();
+ }
+
+ protected void renderCustomView(UsecaseView view) throws UsecaseException {
+ // implement in subclass
+ }
+
+
+ public boolean exists() throws Exception {
+ return true;
+ }
+
+ public String getMimeType(String viewId) throws Exception {
+ return "application/xhtml+xml";
+ }
+
+ public long getSize() throws Exception {
+ // TODO Auto-generated method stub
+ return -1;
+ }
+
+ public ViewDescriptor[] getViewDescriptors() {
+ // TODO: call init() instead of return null
+ if (this.views != null) {
+ ViewDescriptor[] descriptors = new ViewDescriptor[this.views.size()];
+
+ Iterator iter = this.views.keySet().iterator();
+ int i = 0;
+ while (iter.hasNext()) {
+ UsecaseView view = (UsecaseView)iter.next();
+ descriptors[i] = new ViewDescriptor(view.getID());
+ String mimeType = view.getMimeType();
+ if (mimeType == null || mimeType.length() == 0) {
+ mimeType = "application/xhtml+xml";
+ }
+ descriptors[i].setMimeType(mimeType);
+ i++;
+ }
+ return descriptors;
+ }
+ return null;
+ }
+
+}
Property changes on: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseResource.java
___________________________________________________________________
Name: svn:eol-style
+ native
Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseView.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseView.java (rev 0)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseView.java 2007-06-29 14:52:32 UTC (rev 25627)
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.wyona.org/licenses/APACHE-LICENSE-2.0
+ *
+ * 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.wyona.yanel.impl.resources.usecase;
+
+
+import org.wyona.yanel.core.attributes.viewable.View;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.log4j.Category;
+
+/**
+ *
+ */
+public class UsecaseView extends View {
+
+ private static Category log = Category.getInstance(UsecaseView.class);
+
+ public static final String TYPE_JELLY = "jelly";
+ public static final String TYPE_REDIRECT = "redirect";
+ public static final String TYPE_CUSTOM = "custom";
+
+ protected String template;
+ protected String type;
+ protected String id;
+ protected String redirectURL;
+
+ /**
+ *
+ */
+ public UsecaseView(String id, String type) {
+ this.id = id;
+ this.type = type;
+ }
+
+ /**
+ *
+ */
+ public void configure(Configuration config) throws ConfigurationException {
+ if (getType().equals(TYPE_JELLY)) {
+ setTemplate(config.getChild("template").getValue());
+ }
+ if (getType().equals(TYPE_REDIRECT)) {
+ setRedirectURL(config.getChild("url").getValue());
+ }
+ }
+
+ public String getRedirectURL() {
+ return redirectURL;
+ }
+
+ public void setRedirectURL(String redirectURL) {
+ this.redirectURL = redirectURL;
+ }
+
+ public String getTemplate() {
+ return template;
+ }
+
+ public void setTemplate(String template) {
+ this.template = template;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getID() {
+ return this.id;
+ }
+
+}
Property changes on: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/resources/usecase/UsecaseView.java
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Yanel-commits
mailing list