[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