You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by jh...@apache.org on 2005/11/03 15:00:48 UTC
svn commit: r330548 [14/132] - in
/cocoon/whiteboard/maven2/cocoon-flat-layout: ./ cocoon-ajax-block/
cocoon-ajax-block/api/ cocoon-ajax-block/api/src/
cocoon-ajax-block/api/src/main/ cocoon-ajax-block/api/src/main/java/
cocoon-ajax-block/api/src/main/...
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/SimpleCocoonCrawlerImpl.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/SimpleCocoonCrawlerImpl.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/SimpleCocoonCrawlerImpl.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/SimpleCocoonCrawlerImpl.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,650 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.apache.org/licenses/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.apache.cocoon.components.crawler;
+
+import org.apache.avalon.excalibur.pool.Recyclable;
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.cocoon.Constants;
+import org.apache.commons.lang.StringUtils;
+import org.apache.regexp.RE;
+import org.apache.regexp.RESyntaxException;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A simple cocoon crawler.
+ *
+ * @author <a href="mailto:berni_huber@a1.net">Bernhard Huber</a>
+ * @version CVS $Id: SimpleCocoonCrawlerImpl.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class SimpleCocoonCrawlerImpl extends AbstractLogEnabled
+implements CocoonCrawler, Configurable, Disposable, Recyclable {
+
+ /**
+ * Config element name specifying expected link content-typ.
+ * <p>
+ * Its value is <code>link-content-type</code>.
+ * </p>
+ */
+ public final static String LINK_CONTENT_TYPE_CONFIG = "link-content-type";
+
+ /**
+ * Default value of <code>link-content-type</code> configuration value.
+ * <p>
+ * Its value is <code>application/x-cocoon-links</code>.
+ * </p>
+ */
+ public final String LINK_CONTENT_TYPE_DEFAULT = Constants.LINK_CONTENT_TYPE;
+
+ /**
+ * Config element name specifying query-string appendend for requesting links
+ * of an URL.
+ * <p>
+ * Its value is <code>link-view-query</code>.
+ * </p>
+ */
+ public final static String LINK_VIEW_QUERY_CONFIG = "link-view-query";
+
+ /**
+ * Default value of <code>link-view-query</code> configuration option.
+ * <p>
+ * Its value is <code>?cocoon-view=links</code>.
+ * </p>
+ */
+ public final static String LINK_VIEW_QUERY_DEFAULT = "cocoon-view=links";
+
+ /**
+ * Config element name specifying excluding regular expression pattern.
+ * <p>
+ * Its value is <code>exclude</code>.
+ * </p>
+ */
+ public final static String EXCLUDE_CONFIG = "exclude";
+
+ /**
+ * Config element name specifying including regular expression pattern.
+ * <p>
+ * Its value is <code>include</code>.
+ * </p>
+ */
+ public final static String INCLUDE_CONFIG = "include";
+
+ /**
+ * Config element name specifying http header value for user-Agent.
+ * <p>
+ * Its value is <code>user-agent</code>.
+ * </p>
+ */
+ public final static String USER_AGENT_CONFIG = "user-agent";
+
+ /**
+ * Default value of <code>user-agent</code> configuration option.
+ * @see Constants#COMPLETE_NAME
+ */
+ public final static String USER_AGENT_DEFAULT = Constants.COMPLETE_NAME;
+
+ /**
+ * Config element name specifying http header value for accept.
+ * <p>
+ * Its value is <code>accept</code>.
+ * </p>
+ */
+ public final static String ACCEPT_CONFIG = "accept";
+
+ /**
+ * Default value of <code>accept</code> configuration option.
+ * <p>
+ * Its value is <code>* / *</code>
+ * </p>
+ */
+ public final static String ACCEPT_DEFAULT = "*/*";
+
+
+ private String linkViewQuery = LINK_VIEW_QUERY_DEFAULT;
+ private String linkContentType = LINK_CONTENT_TYPE_DEFAULT;
+ private HashSet excludeCrawlingURL;
+ private HashSet includeCrawlingURL;
+ private String userAgent = USER_AGENT_DEFAULT;
+ private String accept = ACCEPT_DEFAULT;
+
+ private int depth;
+
+ private HashSet crawled;
+ private HashSet urlsToProcess;
+ private HashSet urlsNextDepth;
+
+
+
+ /**
+ * Constructor for the SimpleCocoonCrawlerImpl object
+ */
+ public SimpleCocoonCrawlerImpl() {
+ // by default include everything
+ includeCrawlingURL = null;
+ // by default exclude common image patterns
+ excludeCrawlingURL = null;
+ }
+
+
+ /**
+ * Configure the crawler component.
+ * <p>
+ * Configure can specify which URI to include, and which URI to exclude
+ * from crawling. You specify the patterns as regular expressions.
+ * </p>
+ * <p>
+ * Morover you can configure
+ * the required content-type of crawling request, and the
+ * query-string appended to each crawling request.
+ * </p>
+ * <pre><tt>
+ * <include>.*\.html?</exclude> or <exclude>.*\.html?, .*\.xsp</exclude>
+ * <exclude>.*\.gif</exclude> or <exclude>.*\.gif, .*\.jpe?g</exclude>
+ * <link-content-type> application/x-cocoon-links </link-content-type>
+ * <link-view-query> ?cocoon-view=links </link-view-query>
+ * </tt></pre>
+ *
+ * @param configuration XML configuration of this avalon component.
+ * @exception ConfigurationException is throwing if configuration is invalid.
+ */
+ public void configure(Configuration configuration)
+ throws ConfigurationException {
+
+ Configuration[] children;
+ children = configuration.getChildren(INCLUDE_CONFIG);
+ if (children.length > 0) {
+ includeCrawlingURL = new HashSet();
+ for (int i = 0; i < children.length; i++) {
+ String pattern = children[i].getValue();
+ try {
+ String params[] = StringUtils.split(pattern, ", ");
+ for (int index = 0; index < params.length; index++) {
+ String tokenized_pattern = params[index];
+ this.includeCrawlingURL.add(new RE(tokenized_pattern));
+ }
+ } catch (RESyntaxException rese) {
+ getLogger().error("Cannot create including regular-expression for " +
+ pattern, rese);
+ }
+ }
+ } else {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Include all URLs");
+ }
+ }
+
+ children = configuration.getChildren(EXCLUDE_CONFIG);
+ if (children.length > 0) {
+ excludeCrawlingURL = new HashSet();
+ for (int i = 0; i < children.length; i++) {
+ String pattern = children[i].getValue();
+ try {
+ String params[] = StringUtils.split(pattern, ", ");
+ for (int index = 0; index < params.length; index++) {
+ String tokenized_pattern = params[index];
+ this.excludeCrawlingURL.add(new RE(tokenized_pattern));
+ }
+ } catch (RESyntaxException rese) {
+ getLogger().error("Cannot create excluding regular-expression for " +
+ pattern, rese);
+ }
+ }
+ } else {
+ excludeCrawlingURL = new HashSet();
+ setDefaultExcludeFromCrawling();
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Exclude default URLs only");
+ }
+ }
+
+ Configuration child;
+ String value;
+ child = configuration.getChild(LINK_CONTENT_TYPE_CONFIG, false);
+ if (child != null) {
+ value = child.getValue();
+ if (value != null && value.length() > 0) {
+ this.linkContentType = value.trim();
+ }
+ }
+ child = configuration.getChild(LINK_VIEW_QUERY_CONFIG, false);
+ if (child != null) {
+ value = child.getValue();
+ if (value != null && value.length() > 0) {
+ this.linkViewQuery = value.trim();
+ }
+ }
+
+ child = configuration.getChild(USER_AGENT_CONFIG, false);
+ if (child != null) {
+ value = child.getValue();
+ if (value != null && value.length() > 0) {
+ this.userAgent = value;
+ }
+ }
+
+ child = configuration.getChild(ACCEPT_CONFIG, false);
+ if (child != null) {
+ value = child.getValue();
+ if (value != null && value.length() > 0) {
+ this.accept = value;
+ }
+ }
+
+ }
+
+
+ /**
+ * dispose at end of life cycle, releasing all resources.
+ */
+ public void dispose() {
+ crawled = null;
+ urlsToProcess = null;
+ urlsNextDepth = null;
+ excludeCrawlingURL = null;
+ includeCrawlingURL = null;
+ }
+
+
+ /**
+ * recylcle this object, relasing resources
+ */
+ public void recycle() {
+ crawled = null;
+ urlsToProcess = null;
+ urlsNextDepth = null;
+ depth = -1;
+ }
+
+
+ /**
+ * The same as calling crawl(url,-1);
+ *
+ * @param url Crawl this URL, getting all links from this URL.
+ */
+ public void crawl(URL url) {
+ crawl(url, -1);
+ }
+
+ /**
+ * Start crawling a URL.
+ *
+ * <p>
+ * Use this method to start crawling.
+ * Get the this url, and all its children by using <code>iterator()</code>.
+ * The Iterator object will return URL objects.
+ * </p>
+ * <p>
+ * You may use the crawl(), and iterator() methods the following way:
+ * </p>
+ * <pre><tt>
+ * SimpleCocoonCrawlerImpl scci = ....;
+ * scci.crawl( "http://foo/bar" );
+ * Iterator i = scci.iterator();
+ * while (i.hasNext()) {
+ * URL url = (URL)i.next();
+ * ...
+ * }
+ * </tt></pre>
+ * <p>
+ * The i.next() method returns a URL, and calculates the links of the
+ * URL before return it.
+ * </p>
+ *
+ * @param url Crawl this URL, getting all links from this URL.
+ * @param maxDepth maximum depth to crawl to. -1 for no maximum.
+ */
+ public void crawl(URL url, int maxDepth) {
+ crawled = new HashSet();
+ urlsToProcess = new HashSet();
+ urlsNextDepth = new HashSet();
+ depth = maxDepth;
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("crawl URL " + url + " to depth " + maxDepth);
+ }
+
+ urlsToProcess.add(url);
+ }
+
+
+ /**
+ * Return iterator, iterating over all links of the currently crawled URL.
+ * <p>
+ * The Iterator object will return URL objects at its <code>next()</code>
+ * method.
+ * </p>
+ *
+ * @return Iterator iterator of all links from the crawl URL.
+ * @since
+ */
+ public Iterator iterator() {
+ return new CocoonCrawlerIterator(this);
+ }
+
+
+ /**
+ * Default exclude patterns.
+ * <p>
+ * By default URLs matching following patterns are excluded:
+ * </p>
+ * <ul>
+ * <li>.*\\.gif(\\?.*)?$ - exclude gif images</li>
+ * <li>.*\\.png(\\?.*)?$ - exclude png images</li>
+ * <li>.*\\.jpe?g(\\?.*)?$ - exclude jpeg images</li>
+ * <li>.*\\.js(\\?.*)?$ - exclude javascript </li>
+ * <li>.*\\.css(\\?.*)?$ - exclude cascaded stylesheets</li>
+ * </ul>
+ *
+ * @since
+ */
+ private void setDefaultExcludeFromCrawling() {
+ String[] EXCLUDE_FROM_CRAWLING_DEFAULT = {
+ ".*\\.gif(\\?.*)?$",
+ ".*\\.png(\\?.*)?$",
+ ".*\\.jpe?g(\\?.*)?$",
+ ".*\\.js(\\?.*)?$",
+ ".*\\.css(\\?.*)?$"
+ };
+
+ for (int i = 0; i < EXCLUDE_FROM_CRAWLING_DEFAULT.length; i++) {
+ String pattern = EXCLUDE_FROM_CRAWLING_DEFAULT[i];
+ try {
+ excludeCrawlingURL.add(new RE(pattern));
+ } catch (RESyntaxException rese) {
+ getLogger().error("Cannot create excluding regular-expression for " +
+ pattern, rese);
+ }
+ }
+ }
+
+
+ /**
+ * Compute list of links from the url.
+ * <p>
+ * Check for include, exclude pattern, content-type, and if url
+ * has been craweled already.
+ * </p>
+ *
+ * @param url Crawl this URL
+ * @return List of URLs, which are links from url, asserting the conditions.
+ * @since
+ */
+ private List getLinks(URL url) {
+ ArrayList url_links = null;
+ String sURL = url.toString();
+
+ if (!isIncludedURL(sURL) || isExcludedURL(sURL)) {
+ return null;
+ }
+
+ // don't try to get links for url which has been crawled already
+ if (crawled.contains(sURL)) {
+ return null;
+ }
+
+ // mark it as crawled
+ crawled.add(sURL);
+
+ // get links of url
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Getting links of URL " + sURL);
+ }
+ BufferedReader br = null;
+ try {
+ sURL = url.getFile();
+ URL links = new URL(url, sURL
+ + ((sURL.indexOf("?") == -1) ? "?" : "&")
+ + linkViewQuery);
+ URLConnection links_url_connection = links.openConnection();
+ links_url_connection.setRequestProperty("Accept", accept);
+ links_url_connection.setRequestProperty("User-Agent", userAgent);
+ links_url_connection.connect();
+ InputStream is = links_url_connection.getInputStream();
+ br = new BufferedReader(new InputStreamReader(is));
+
+ String contentType = links_url_connection.getContentType();
+ if (contentType == null) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Ignoring " + sURL + " (no content type)");
+ }
+ // there is a check on null in the calling method
+ return null;
+ }
+
+ int index = contentType.indexOf(';');
+ if (index != -1) {
+ contentType = contentType.substring(0, index);
+ }
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Content-type: " + contentType);
+ }
+
+ if (contentType.equals(linkContentType)) {
+ url_links = new ArrayList();
+
+ // content is supposed to be a list of links,
+ // relative to current URL
+ String line;
+ while ((line = br.readLine()) != null) {
+ final URL newUrl = new URL(url, line);
+ final String sNewUrl = newUrl.toString();
+
+ boolean add_url = true;
+ // don't add new_url twice
+ if (add_url) {
+ add_url &= !url_links.contains(sNewUrl);
+ }
+
+ // don't add new_url if it has been crawled already
+ if (add_url) {
+ add_url &= !crawled.contains(sNewUrl);
+ }
+
+ // don't add if is not matched by existing include definition
+ if (add_url) {
+ add_url &= isIncludedURL(sNewUrl);
+ }
+
+ // don't add if is matched by existing exclude definition
+ if (add_url) {
+ add_url &= !isExcludedURL(sNewUrl);
+ }
+ if (add_url) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Add URL: " + sNewUrl);
+ }
+ url_links.add(newUrl);
+ }
+ }
+ // now we have a list of URL which should be examined
+ }
+ } catch (IOException ioe) {
+ getLogger().warn("Problems get links of " + url, ioe);
+ } finally {
+ if (br != null) {
+ try {
+ br.close();
+ br = null;
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ return url_links;
+ }
+
+
+ /**
+ * check if URL is a candidate for indexing
+ *
+ * @param url the URL to check
+ * @return The excludedURL value
+ */
+ private boolean isExcludedURL(String url) {
+ // by default do not exclude URL for crawling
+ if (excludeCrawlingURL == null) {
+ return false;
+ }
+
+ final String s = url.toString();
+ Iterator i = excludeCrawlingURL.iterator();
+ while (i.hasNext()) {
+ RE pattern = (RE) i.next();
+ if (pattern.match(s)) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Excluded URL " + url);
+ }
+ return true;
+ }
+ }
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Not excluded URL " + url);
+ }
+ return false;
+ }
+
+
+ /**
+ * check if URL is a candidate for indexing
+ *
+ * @param url Description of Parameter
+ * @return The includedURL value
+ */
+ private boolean isIncludedURL(String url) {
+ // by default include URL for crawling
+ if (includeCrawlingURL == null) {
+ return true;
+ }
+
+ final String s = url.toString();
+ Iterator i = includeCrawlingURL.iterator();
+ while (i.hasNext()) {
+ RE pattern = (RE) i.next();
+ if (pattern.match(s)) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Included URL " + url);
+ }
+ return true;
+ }
+ }
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Not included URL " + url);
+ }
+ return false;
+ }
+
+
+ /**
+ * Helper class implementing an Iterator
+ * <p>
+ * This Iterator implementation calculates the links of an URL
+ * before returning in the next() method.
+ * </p>
+ *
+ * @author <a href="mailto:berni_huber@a1.net">Bernhard Huber</a>
+ * @version $Id: SimpleCocoonCrawlerImpl.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+ public static class CocoonCrawlerIterator implements Iterator {
+ private SimpleCocoonCrawlerImpl cocoonCrawler;
+
+
+ /**
+ * Constructor for the CocoonCrawlerIterator object
+ *
+ * @param cocoonCrawler the containing CocoonCrawler instance.
+ */
+ CocoonCrawlerIterator(SimpleCocoonCrawlerImpl cocoonCrawler) {
+ this.cocoonCrawler = cocoonCrawler;
+ }
+
+
+ /**
+ * check if crawling is finished.
+ *
+ * @return <code>true</code> if crawling has finished,
+ * else <code>false</code>.
+ */
+ public boolean hasNext() {
+ return cocoonCrawler.urlsToProcess.size() > 0
+ || cocoonCrawler.urlsNextDepth.size() > 0;
+ }
+
+
+ /**
+ * @return the next URL
+ */
+ public Object next() {
+ if (cocoonCrawler.urlsToProcess.size() == 0
+ && cocoonCrawler.urlsNextDepth.size() > 0) {
+ // process queued urls belonging to the next depth level
+ cocoonCrawler.urlsToProcess = cocoonCrawler.urlsNextDepth;
+ cocoonCrawler.urlsNextDepth = new HashSet();
+ // fix Bugzilla Bug 25270
+ // only decrease if depth > 0, excluding decreasing
+ // if depth is already equal to -1
+ if (cocoonCrawler.depth > 0) {
+ cocoonCrawler.depth--;
+ }
+ }
+ URL theNextUrl = null;
+ // fix Bugzilla Bug 25270
+ // return NextUrl != null only if getLinks() returns non-null
+ // list
+ for (Iterator i = cocoonCrawler.urlsToProcess.iterator();
+ i.hasNext() && theNextUrl == null;) {
+ // fetch a URL
+ URL url = (URL) i.next();
+
+ // remove it from the to-do list
+ i.remove();
+
+ if (cocoonCrawler.depth == -1 || cocoonCrawler.depth > 0) {
+ // calc all links from this url
+ List url_links = cocoonCrawler.getLinks(url);
+ if (url_links != null) {
+ // add links of this url to the to-do list
+ cocoonCrawler.urlsNextDepth.addAll(url_links);
+ theNextUrl = url;
+ }
+ }
+ }
+ // finally return url
+ return theNextUrl;
+ }
+
+
+ /**
+ * remove is not implemented
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("remove is not implemented");
+ }
+ }
+}
+
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/SimpleCocoonCrawlerImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/package.html
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/package.html?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/package.html (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/package.html Thu Nov 3 05:41:06 2005
@@ -0,0 +1,33 @@
+<!--
+ Copyright 1999-2004 The Apache Software Foundation
+
+ 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.apache.org/licenses/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.
+-->
+<html>
+<head>
+ <title>Crawler - starts from a given URL and follows the links</title>
+</head>
+<body>
+ <h1>Crawler - starts from a given URL and follows the links</h1>
+ <p>
+ This package provides Cocoon crawler components.
+ </p>
+ <p>
+ A crawler component crawls through URLs.
+ The process is initiated by calling <code>crawl()</code>.
+ The method <code>iterator()</code> returns an Iterator object.
+ This Iterator object iterates over all URLs reachable from
+ the passed URL of method <code>crawl()</code>.
+ </p>
+</body>
+</html>
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/crawler/package.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitor.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitor.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitor.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitor.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2002-2005 The Apache Software Foundation
+ * 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.apache.org/licenses/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.apache.cocoon.components.fam;
+
+import org.apache.commons.jci.monitor.FilesystemAlterationListener;
+
+public interface SitemapMonitor {
+ String ROLE = SitemapMonitor.class.getName();
+
+ void subscribe(final FilesystemAlterationListener listener);
+ void unsubscribe(final FilesystemAlterationListener listener);
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitor.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2002-2005 The Apache Software Foundation
+ * 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.apache.org/licenses/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.apache.cocoon.components.fam;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.commons.jci.monitor.FilesystemAlterationListener;
+import org.apache.commons.jci.monitor.FilesystemAlterationMonitor;
+import org.apache.excalibur.source.SourceResolver;
+
+public final class SitemapMonitorImpl extends AbstractLogEnabled implements SitemapMonitor, Serviceable, ThreadSafe, Initializable, Disposable {
+
+ private ServiceManager manager;
+ private SourceResolver resolver;
+ private FilesystemAlterationMonitor monitor;
+
+ public void service( ServiceManager manager ) throws ServiceException {
+ this.manager = manager;
+ this.resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
+ }
+
+ public void initialize() throws Exception {
+ monitor = new FilesystemAlterationMonitor();
+ monitor.start();
+ }
+
+ public void dispose() {
+ monitor.stop();
+ }
+
+ public void subscribe(final FilesystemAlterationListener listener) {
+ monitor.addListener(listener);
+ }
+
+ public void unsubscribe(final FilesystemAlterationListener listener) {
+ monitor.removeListener(listener);
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/AbstractInterpreter.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/AbstractInterpreter.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/AbstractInterpreter.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/AbstractInterpreter.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,210 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.apache.org/licenses/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.apache.cocoon.components.flow;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.SingleThreaded;
+import org.apache.cocoon.Constants;
+import org.apache.cocoon.components.ContextHelper;
+import org.apache.cocoon.components.flow.util.PipelineUtil;
+import org.apache.cocoon.environment.Context;
+import org.apache.cocoon.environment.Redirector;
+import org.apache.excalibur.source.SourceUtil;
+
+/**
+ * Abstract superclass for various scripting languages used by Cocoon
+ * for flow control. Defines some useful behavior like the ability to
+ * reload script files if they get modified (useful when doing
+ * development), and passing the control to Cocoon's sitemap for
+ * result page generation.
+ * <p>
+ * Flow intrepreters belonging to different sitemaps should be isolated. To achieve this,
+ * class implements the {@link org.apache.avalon.framework.thread.SingleThreaded}. Since
+ * the sitemap engine looks up the flow intepreter once at sitemap build time, this ensures
+ * that each sitemap will use a different instance of this class. But that instance will
+ * handle all flow calls for a given sitemap, and must therefore be thread safe.
+ *
+ * @author <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ * @since March 15, 2002
+ * @version CVS $Id: AbstractInterpreter.java 123711 2004-12-30 10:23:03Z cziegeler $
+ */
+public abstract class AbstractInterpreter
+ extends AbstractLogEnabled
+ implements Serviceable, Contextualizable, Interpreter,
+ SingleThreaded, Configurable, Disposable {
+
+ // The instance ID of this interpreter, used to identify user scopes
+ private String instanceID;
+
+ protected org.apache.avalon.framework.context.Context avalonContext;
+
+ /**
+ * List of source locations that need to be resolved.
+ */
+ protected ArrayList needResolve = new ArrayList();
+
+ protected org.apache.cocoon.environment.Context context;
+ protected ServiceManager manager;
+ protected ContinuationsManager continuationsMgr;
+
+ /**
+ * Whether reloading of scripts should be done. Specified through
+ * the "reload-scripts" attribute in <code>flow.xmap</code>.
+ */
+ protected boolean reloadScripts;
+
+ /**
+ * Interval between two checks for modified script files. Specified
+ * through the "check-time" XML attribute in <code>flow.xmap</code>.
+ */
+ protected long checkTime;
+
+ /**
+ * Set the unique ID for this interpreter, which can be used to distinguish user value scopes
+ * attached to the session.
+ */
+ public void setInterpreterID(String interpreterID) {
+ this.instanceID = interpreterID;
+ }
+
+ /**
+ * Get the unique ID for this interpreter, which can be used to distinguish user value scopes
+ * attached to the session.
+ *
+ * @return a unique ID for this interpreter
+ */
+ public String getInterpreterID() {
+ return this.instanceID;
+ }
+
+ public void configure(Configuration config) throws ConfigurationException {
+ reloadScripts = config.getChild("reload-scripts").getValueAsBoolean(false);
+ checkTime = config.getChild("check-time").getValueAsLong(1000L);
+ }
+
+ /**
+ * Serviceable
+ */
+ public void service(ServiceManager sm) throws ServiceException {
+ this.manager = sm;
+ this.continuationsMgr = (ContinuationsManager)sm.lookup(ContinuationsManager.ROLE);
+ }
+
+ public void contextualize(org.apache.avalon.framework.context.Context context)
+ throws ContextException{
+ this.avalonContext = context;
+ this.context = (Context)context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.avalon.framework.activity.Disposable#dispose()
+ */
+ public void dispose() {
+ if ( this.manager != null ) {
+ this.manager.release( this.continuationsMgr );
+ this.continuationsMgr = null;
+ this.manager = null;
+ }
+ }
+
+ /**
+ * Registers a source file with the interpreter. Using this method
+ * an implementation keeps track of all the script files which are
+ * compiled. This allows them to reload the script files which get
+ * modified on the file system.
+ *
+ * <p>The parsing/compilation of a script file by an interpreter
+ * happens in two phases. In the first phase the file's location is
+ * registered in the <code>needResolve</code> array.
+ *
+ * <p>The second is possible only when a Cocoon
+ * <code>Environment</code> is passed to the Interpreter. This
+ * allows the file location to be resolved using Cocoon's
+ * <code>SourceFactory</code> class.
+ *
+ * <p>Once a file's location can be resolved, it is removed from the
+ * <code>needResolve</code> array and placed in the
+ * <code>scripts</code> hash table. The key in this hash table is
+ * the file location string, and the value is a
+ * DelayedRefreshSourceWrapper instance which keeps track of when
+ * the file needs to re-read.
+ *
+ * @param source the location of the script
+ *
+ * @see org.apache.cocoon.environment.Environment
+ * @see org.apache.cocoon.components.source.impl.DelayedRefreshSourceWrapper
+ */
+ public void register(String source) {
+ synchronized (this) {
+ needResolve.add(source);
+ }
+ }
+
+ /**
+ * Call the Cocoon sitemap for the given URI, sending the output of the
+ * eventually matched pipeline to the specified outputstream.
+ *
+ * @param uri The URI for which the request should be generated.
+ * @param biz Extra data associated with the subrequest.
+ * @param out An OutputStream where the output should be written to.
+ * @exception Exception If an error occurs.
+ */
+ public void process(String uri, Object biz, OutputStream out)
+ throws Exception {
+ // FIXME (SW): should we deprecate this method in favor of PipelineUtil?
+ PipelineUtil pipeUtil = new PipelineUtil();
+ try {
+ pipeUtil.contextualize(this.avalonContext);
+ pipeUtil.service(this.manager);
+ pipeUtil.processToStream(uri, biz, out);
+ } finally {
+ pipeUtil.dispose();
+ }
+ }
+
+ public void forwardTo(String uri, Object bizData,
+ WebContinuation continuation,
+ Redirector redirector)
+ throws Exception {
+ if (SourceUtil.indexOfSchemeColon(uri) == -1) {
+ uri = "cocoon:/" + uri;
+ Map objectModel = ContextHelper.getObjectModel(this.avalonContext);
+ FlowHelper.setWebContinuation(objectModel, continuation);
+ FlowHelper.setContextObject(objectModel, bizData);
+ if (redirector.hasRedirected()) {
+ throw new IllegalStateException("Pipeline has already been processed for this request");
+ }
+ // this is a hint for the redirector
+ objectModel.put("cocoon:forward", "true");
+ redirector.redirect(false, uri);
+ } else {
+ throw new Exception("uri is not allowed to contain a scheme (cocoon:/ is always automatically used)");
+ }
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/AbstractInterpreter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/CompilingInterpreter.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/CompilingInterpreter.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/CompilingInterpreter.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/CompilingInterpreter.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,120 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.apache.org/licenses/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.apache.cocoon.components.flow;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceResolver;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Script;
+import org.mozilla.javascript.Scriptable;
+
+/**
+ * This is a base class for all interpreters compiling the scripts
+ *
+ * @author <a href="mailto:ovidiu@apache.org">Ovidiu Predescu</a>
+ * @author <a href="mailto:crafterm@apache.org">Marcus Crafter</a>
+ * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
+ * @version CVS $Id: CompilingInterpreter.java 55850 2004-10-28 13:43:12Z vgritsenko $
+ */
+public abstract class CompilingInterpreter
+ extends AbstractInterpreter {
+
+ /**
+ * A source resolver
+ */
+ protected SourceResolver sourceresolver;
+
+ /**
+ * Mapping of String objects (source uri's) to ScriptSourceEntry's
+ */
+ protected Map compiledScripts = new HashMap();
+
+ /* (non-Javadoc)
+ * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
+ */
+ public void service(ServiceManager manager) throws ServiceException {
+ super.service(manager);
+ this.sourceresolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.avalon.framework.activity.Disposable#dispose()
+ */
+ public void dispose() {
+ if (this.compiledScripts != null) {
+ Iterator i = this.compiledScripts.values().iterator();
+ while (i.hasNext()) {
+ ScriptSourceEntry current = (ScriptSourceEntry)i.next();
+ this.sourceresolver.release(current.getSource());
+ }
+ this.compiledScripts = null;
+ }
+ if (this.manager != null) {
+ this.manager.release(this.sourceresolver);
+ this.sourceresolver = null;
+ }
+ super.dispose();
+ }
+
+ /**
+ * TODO - This is a little bit strange, the interpreter calls
+ * get Script on the ScriptSourceEntry which in turn
+ * calls compileScript on the interpreter. I think we
+ * need more refactoring here.
+ */
+ protected abstract Script compileScript(Context context,
+ Scriptable scope,
+ Source source) throws Exception;
+
+ protected class ScriptSourceEntry {
+ final private Source source;
+ private Script script;
+ private long compileTime;
+
+ public ScriptSourceEntry(Source source) {
+ this.source = source;
+ }
+
+ public ScriptSourceEntry(Source source, Script script, long t) {
+ this.source = source;
+ this.script = script;
+ this.compileTime = t;
+ }
+
+ public Source getSource() {
+ return source;
+ }
+
+ public Script getScript(Context context, Scriptable scope,
+ boolean refresh, CompilingInterpreter interpreter)
+ throws Exception {
+ if (refresh) {
+ source.refresh();
+ }
+ if (script == null || compileTime < source.getLastModified()) {
+ script = interpreter.compileScript(context, scope, source);
+ compileTime = source.getLastModified();
+ }
+ return script;
+ }
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/CompilingInterpreter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsDisposer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsDisposer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsDisposer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsDisposer.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.apache.org/licenses/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.apache.cocoon.components.flow;
+
+/**
+ * ContinuationsDisposer declares the contract for the clean-up of specfic
+ * continuations.
+ * <p>
+ * Typically a {@link Interpreter} implementation that produces continuation
+ * objects which require proper clean up will implement this interface to get
+ * a call-back in the event of the ContinuationsManager deciding to invalidate
+ * a WebContinuation.
+ */
+public interface ContinuationsDisposer {
+ /**
+ * Disposes the passed continuation object.
+ * <p>
+ * This method is called from the ContinuationsManager in the event of
+ * the invalidation of a continuation upon the {@link ContinuationsDisposer}
+ * object passed during the creation of the WebContinuation.
+ *
+ * @param webContinuation the {@link WebContinuation} value representing the
+ * continuation object.
+ */
+ public void disposeContinuation(WebContinuation webContinuation);
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsDisposer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManager.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManager.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManager.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManager.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.apache.org/licenses/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.apache.cocoon.components.flow;
+
+import java.util.List;
+
+/**
+ * The interface of the Continuations manager.
+ *
+ * The continuation manager maintains a forrest of {@link
+ * WebContinuation} trees. Each tree defines the flow of control for a
+ * user within the application.
+ *
+ * A <code>WebContinuation</code> is created for a continuation object
+ * from the scripting language used. A continuation object in the
+ * implementation of the scripting language is an opaque object
+ * here. It is only stored inside the <code>WebContinuation</code>,
+ * without being interpreted in any way.
+ *
+ * @author <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ * @since March 19, 2002
+ * @see WebContinuation
+ * @version CVS $Id: ContinuationsManager.java 164239 2005-04-22 13:54:29Z reinhard $
+ */
+public interface ContinuationsManager {
+ public final String ROLE = ContinuationsManager.class.getName();
+
+ /**
+ * Create a <code>WebContinuation</code> object given a native
+ * continuation object and its parent. If the parent continuation is
+ * null, the <code>WebContinuation</code> returned becomes the root
+ * of a tree in the forrest.
+ *
+ * @param kont an <code>Object</code> value
+ * @param parentKont a <code>WebContinuation</code> value
+ * @param timeToLive an <code>int</code> value indicating how long
+ * in seconds this continuation will live in the server if not
+ * accessed
+ * @param interpreterId id of interpreter invoking continuation creation
+ * @param disposer a <code>ContinuationsDisposer</code> instance to called when
+ * the continuation gets cleaned up.
+ * @return a <code>WebContinuation</code> value
+ * @see WebContinuation
+ */
+ public WebContinuation createWebContinuation(Object kont,
+ WebContinuation parentKont,
+ int timeToLive,
+ String interpreterId,
+ ContinuationsDisposer disposer);
+
+ /**
+ * Invalidates a <code>WebContinuation</code>. This effectively
+ * means that the continuation object associated with it will no
+ * longer be accessible from Web pages. Invalidating a
+ * <code>WebContinuation</code> invalidates all the
+ * <code>WebContinuation</code>s which are children of it.
+ *
+ * @param k a <code>WebContinuation</code> value
+ */
+ public void invalidateWebContinuation(WebContinuation k);
+
+ /**
+ * Given a <code>WebContinuation</code> id, retrieve the associated
+ * <code>WebContinuation</code> object.
+ * @param id a <code>String</code> value
+ * @param interpreterId Id of an interpreter that queries for
+ * the continuation
+ *
+ * @return a <code>WebContinuation</code> object, null if no such
+ * <code>WebContinuation</code> could be found. Also null if
+ * <code>WebContinuation</code> was found but interpreter id does
+ * not match the one that the continuation was initialy created for.
+ */
+ public WebContinuation lookupWebContinuation(String id, String interpreterId);
+
+ /**
+ * Prints debug information about all web continuations into the log file.
+ * @see WebContinuation#display()
+ */
+ public void displayAllContinuations();
+
+ /**
+ * Get a list of all continuations as <code>WebContinuationDataBean</code> objects.
+ */
+ public List getWebContinuationsDataBeanList();
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManager.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManagerImpl.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManagerImpl.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManagerImpl.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManagerImpl.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,581 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.apache.org/licenses/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.apache.cocoon.components.flow;
+
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.components.ContextHelper;
+import org.apache.cocoon.components.thread.RunnableManager;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.Session;
+
+
+/**
+ * The default implementation of {@link ContinuationsManager}. <br/>There are
+ * two modes of work: <br/>
+ * <ul>
+ * <li><b>standard mode </b>- continuations are stored in single holder. No
+ * security is applied to continuation lookup. Anyone can invoke a continuation
+ * only knowing the ID. Set "session-bound-continuations" configuration option
+ * to false to activate this mode.</li>
+ * <li><b>secure mode </b>- each session has it's own continuations holder. A
+ * continuation is only valid for the same session it was created for. Session
+ * invalidation causes all bound continuations to be invalidated as well. Use
+ * this setting for web applications. Set "session-bound-continuations"
+ * configuration option to true to activate this mode.</li>
+ * </ul>
+ *
+ * @author <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu </a>
+ * @author <a href="mailto:Michael.Melhem@managesoft.com">Michael Melhem </a>
+ * @since March 19, 2002
+ * @see ContinuationsManager
+ * @version CVS $Id: ContinuationsManagerImpl.java 293111 2005-10-02 13:39:20Z reinhard $
+ */
+public class ContinuationsManagerImpl
+ extends AbstractLogEnabled
+ implements ContinuationsManager, Configurable, ThreadSafe, Serviceable, Contextualizable {
+
+ static final int CONTINUATION_ID_LENGTH = 20;
+ static final String EXPIRE_CONTINUATIONS = "expire-continuations";
+
+ /**
+ * Random number generator used to create continuation ID
+ */
+ protected SecureRandom random;
+ protected byte[] bytes;
+
+ /**
+ * How long does a continuation exist in memory since the last
+ * access? The time is in miliseconds, and the default is 1 hour.
+ */
+ protected int defaultTimeToLive;
+
+ /**
+ * Maintains the forest of <code>WebContinuation</code> trees.
+ * This set is used only for debugging puroses by
+ * {@link #displayAllContinuations()} method.
+ */
+ protected Set forest = Collections.synchronizedSet(new HashSet());
+
+ /**
+ * Main continuations holder. Used unless continuations are stored in user
+ * session.
+ */
+ protected WebContinuationsHolder continuationsHolder;
+
+ /**
+ * Sorted set of <code>WebContinuation</code> instances, based on
+ * their expiration time. This is used by the background thread to
+ * invalidate continuations.
+ */
+ protected SortedSet expirations = Collections.synchronizedSortedSet(new TreeSet());
+
+ protected boolean bindContinuationsToSession;
+
+ protected ServiceManager serviceManager;
+ protected Context context;
+
+ public ContinuationsManagerImpl() throws Exception {
+ try {
+ random = SecureRandom.getInstance("SHA1PRNG");
+ } catch(java.security.NoSuchAlgorithmException nsae) {
+ // Maybe we are on IBM's SDK
+ random = SecureRandom.getInstance("IBMSecureRandom");
+ }
+ random.setSeed(System.currentTimeMillis());
+ bytes = new byte[CONTINUATION_ID_LENGTH];
+ }
+
+ public void service(ServiceManager manager) throws ServiceException {
+ this.serviceManager = manager;
+ }
+
+ public void configure(Configuration config) {
+ this.defaultTimeToLive = config.getAttributeAsInteger("time-to-live", (3600 * 1000));
+ this.bindContinuationsToSession = config.getAttributeAsBoolean( "session-bound-continuations", false );
+ // create a global ContinuationsHolder if this the "session-bound-continuations" parameter is set to false
+ if (!this.bindContinuationsToSession) {
+ this.continuationsHolder = new WebContinuationsHolder();
+ }
+
+ final Configuration expireConf = config.getChild("expirations-check");
+ final long initialDelay = expireConf.getChild("offset", true).getValueAsLong(180000);
+ final long interval = expireConf.getChild("period", true).getValueAsLong(180000);
+ try {
+ final RunnableManager runnableManager = (RunnableManager)serviceManager.lookup(RunnableManager.ROLE);
+ runnableManager.execute( new Runnable() {
+ public void run()
+ {
+ expireContinuations();
+ }
+ }, initialDelay, interval);
+ serviceManager.release(runnableManager);
+ } catch (Exception e) {
+ getLogger().warn("Could not enqueue continuations expiration task. " +
+ "Continuations will not automatically expire.", e);
+ }
+ }
+
+
+ public WebContinuation createWebContinuation(Object kont,
+ WebContinuation parent,
+ int timeToLive,
+ String interpreterId,
+ ContinuationsDisposer disposer) {
+ int ttl = (timeToLive == 0 ? defaultTimeToLive : timeToLive);
+
+ WebContinuation wk = generateContinuation(kont, parent, ttl, interpreterId, disposer);
+ wk.enableLogging(getLogger());
+
+ if (parent == null) {
+ forest.add(wk);
+ } else {
+ handleParentContinuationExpiration(parent);
+ }
+
+ handleLeafContinuationExpiration(wk);
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK: Created continuation " + wk.getId());
+ }
+
+ return wk;
+ }
+
+ /**
+ * When a new continuation is created in @link #createWebContinuation(Object, WebContinuation, int, String, ContinuationsDisposer),
+ * it is registered in the expiration set in order to be evaluated by the invalidation mechanism.
+ */
+ protected void handleLeafContinuationExpiration(WebContinuation wk) {
+ expirations.add(wk);
+ }
+
+ /**
+ * When a new continuation is created in @link #createWebContinuation(Object, WebContinuation, int, String, ContinuationsDisposer),
+ * its parent continuation is removed from the expiration set. This way only leaf continuations are part of
+ * the expiration set.
+ */
+ protected void handleParentContinuationExpiration(WebContinuation parent) {
+ if (parent.getChildren().size() < 2) {
+ expirations.remove(parent);
+ }
+ }
+
+ /**
+ * Get a list of all web continuations (data only)
+ */
+ public List getWebContinuationsDataBeanList() {
+ List beanList = new ArrayList();
+ for(Iterator it = this.forest.iterator(); it.hasNext();) {
+ beanList.add(new WebContinuationDataBean((WebContinuation) it.next()));
+ }
+ return beanList;
+ }
+
+ public WebContinuation lookupWebContinuation(String id, String interpreterId) {
+ // REVISIT: Is the following check needed to avoid threading issues:
+ // return wk only if !(wk.hasExpired) ?
+ WebContinuationsHolder continuationsHolder = lookupWebContinuationsHolder(false);
+ if (continuationsHolder == null)
+ return null;
+
+ WebContinuation kont = continuationsHolder.get(id);
+ if (kont == null)
+ return null;
+
+ if (!kont.interpreterMatches(interpreterId)) {
+ getLogger().error(
+ "WK: Continuation (" + kont.getId()
+ + ") lookup for wrong interpreter. Bound to: "
+ + kont.getInterpreterId() + ", looked up for: "
+ + interpreterId);
+ return null;
+ }
+ return kont;
+ }
+
+ /**
+ * Create <code>WebContinuation</code> and generate unique identifier for
+ * it. The identifier is generated using a cryptographically strong
+ * algorithm to prevent people to generate their own identifiers.
+ *
+ * <p>
+ * It has the side effect of interning the continuation object in the
+ * <code>idToWebCont</code> hash table.
+ *
+ * @param kont
+ * an <code>Object</code> value representing continuation
+ * @param parent
+ * value representing parent <code>WebContinuation</code>
+ * @param ttl
+ * <code>WebContinuation</code> time to live
+ * @param interpreterId
+ * id of interpreter invoking continuation creation
+ * @param disposer
+ * <code>ContinuationsDisposer</code> instance to use for
+ * cleanup of the continuation.
+ * @return the generated <code>WebContinuation</code> with unique
+ * identifier
+ */
+ protected WebContinuation generateContinuation(Object kont,
+ WebContinuation parent,
+ int ttl,
+ String interpreterId,
+ ContinuationsDisposer disposer) {
+
+ char[] result = new char[bytes.length * 2];
+ WebContinuation wk = null;
+ WebContinuationsHolder continuationsHolder = lookupWebContinuationsHolder(true);
+ while (true) {
+ random.nextBytes(bytes);
+
+ for (int i = 0; i < CONTINUATION_ID_LENGTH; i++) {
+ byte ch = bytes[i];
+ result[2 * i] = Character.forDigit(Math.abs(ch >> 4), 16);
+ result[2 * i + 1] = Character.forDigit(Math.abs(ch & 0x0f), 16);
+ }
+
+ final String id = new String(result);
+ synchronized (continuationsHolder) {
+ if (!continuationsHolder.contains(id)) {
+ if (this.bindContinuationsToSession)
+ wk = new HolderAwareWebContinuation(id, kont, parent,
+ ttl, interpreterId, disposer,
+ continuationsHolder);
+ else
+ wk = new WebContinuation(id, kont, parent, ttl,
+ interpreterId, disposer);
+ continuationsHolder.addContinuation(wk);
+ break;
+ }
+ }
+ }
+
+ return wk;
+ }
+
+ public void invalidateWebContinuation(WebContinuation wk) {
+ WebContinuationsHolder continuationsHolder = lookupWebContinuationsHolder(false);
+ if (!continuationsHolder.contains(wk)) {
+ //TODO this looks like a security breach - should we throw?
+ return;
+ }
+ _detach(wk);
+ _invalidate(continuationsHolder, wk);
+ }
+
+ private void _invalidate(WebContinuationsHolder continuationsHolder, WebContinuation wk) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK: Manual expire of continuation " + wk.getId());
+ }
+ disposeContinuation(continuationsHolder, wk);
+ expirations.remove(wk);
+
+ // Invalidate all the children continuations as well
+ List children = wk.getChildren();
+ int size = children.size();
+ for (int i = 0; i < size; i++) {
+ _invalidate(continuationsHolder, (WebContinuation) children.get(i));
+ }
+ }
+
+ /**
+ * Detach this continuation from parent. This method removes
+ * continuation from {@link #forest} set, or, if it has parent,
+ * from parent's children collection.
+ * @param continuationsHolder
+ * @param wk Continuation to detach from parent.
+ */
+ protected void _detach(WebContinuation wk) {
+ WebContinuation parent = wk.getParentContinuation();
+ if (parent == null) {
+ forest.remove(wk);
+ } else
+ wk.detachFromParent();
+ }
+
+ /**
+ * Makes the continuation inaccessible for lookup, and triggers possible needed
+ * cleanup code through the ContinuationsDisposer interface.
+ * @param continuationsHolder
+ *
+ * @param wk the continuation to dispose.
+ */
+ protected void disposeContinuation(WebContinuationsHolder continuationsHolder, WebContinuation wk) {
+ continuationsHolder.removeContinuation(wk);
+ wk.dispose();
+ }
+
+ /**
+ * Removes an expired leaf <code>WebContinuation</code> node
+ * from its continuation tree, and recursively removes its
+ * parent(s) if it they have expired and have no (other) children.
+ * @param continuationsHolder
+ *
+ * @param wk <code>WebContinuation</code> node
+ */
+ protected void removeContinuation(WebContinuationsHolder continuationsHolder,
+ WebContinuation wk) {
+ if (wk.getChildren().size() != 0) {
+ return;
+ }
+
+ // remove access to this contination
+ disposeContinuation(continuationsHolder, wk);
+ _detach(wk);
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK: Deleted continuation: " + wk.getId());
+ }
+
+ // now check if parent needs to be removed.
+ WebContinuation parent = wk.getParentContinuation();
+ if (null != parent && parent.hasExpired()) {
+ //parent must have the same continuations holder, lookup not needed
+ removeContinuation(continuationsHolder, parent);
+ }
+ }
+
+ /**
+ * Dump to Log file the current contents of
+ * the expirations <code>SortedSet</code>
+ */
+ protected void displayExpireSet() {
+ StringBuffer wkSet = new StringBuffer("\nWK; Expire set size: " + expirations.size());
+ Iterator i = expirations.iterator();
+ while (i.hasNext()) {
+ final WebContinuation wk = (WebContinuation) i.next();
+ final long lat = wk.getLastAccessTime() + wk.getTimeToLive();
+ wkSet.append("\nWK: ")
+ .append(wk.getId())
+ .append(" ExpireTime [");
+
+ if (lat < System.currentTimeMillis()) {
+ wkSet.append("Expired");
+ } else {
+ wkSet.append(lat);
+ }
+ wkSet.append("]");
+ }
+
+ getLogger().debug(wkSet.toString());
+ }
+
+ /**
+ * Dump to Log file all <code>WebContinuation</code>s
+ * in the system
+ */
+ public void displayAllContinuations() {
+ final Iterator i = forest.iterator();
+ while (i.hasNext()) {
+ ((WebContinuation) i.next()).display();
+ }
+ }
+
+ /**
+ * Remove all continuations which have already expired.
+ */
+ protected void expireContinuations() {
+ long now = 0;
+ if (getLogger().isDebugEnabled()) {
+ now = System.currentTimeMillis();
+
+ /* Continuations before clean up:
+ getLogger().debug("WK: Forest before cleanup: " + forest.size());
+ displayAllContinuations();
+ displayExpireSet();
+ */
+ }
+
+ // Clean up expired continuations
+ int count = 0;
+ WebContinuation wk;
+ Iterator i = expirations.iterator();
+ while (i.hasNext() && ((wk = (WebContinuation) i.next()).hasExpired())) {
+ i.remove();
+ WebContinuationsHolder continuationsHolder = null;
+ if ( wk instanceof HolderAwareWebContinuation )
+ continuationsHolder = ((HolderAwareWebContinuation) wk).getContinuationsHolder();
+ else
+ continuationsHolder = this.continuationsHolder;
+ removeContinuation(continuationsHolder, wk);
+ count++;
+ }
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK Cleaned up " + count + " continuations in " +
+ (System.currentTimeMillis() - now));
+
+ /* Continuations after clean up:
+ getLogger().debug("WK: Forest after cleanup: " + forest.size());
+ displayAllContinuations();
+ displayExpireSet();
+ */
+ }
+ }
+
+ /**
+ * Method used by WebContinuationsHolder to notify the continuations manager
+ * about session invalidation. Invalidates all continuations held by passed
+ * continuationsHolder.
+ */
+ protected void invalidateContinuations(
+ WebContinuationsHolder continuationsHolder) {
+ // TODO: this avoids ConcurrentModificationException, still this is not
+ // the best solution and should be changed
+ Object[] continuationIds = continuationsHolder.getContinuationIds()
+ .toArray();
+
+ for (int i = 0; i < continuationIds.length; i++) {
+ WebContinuation wk = continuationsHolder.get(continuationIds[i]);
+ if (wk != null) {
+ _detach(wk);
+ _invalidate(continuationsHolder, wk);
+ }
+ }
+ }
+
+ /**
+ * Lookup a proper web continuations holder.
+ * @param createNew
+ * should the manager create a continuations holder in session
+ * when none found?
+ */
+ public WebContinuationsHolder lookupWebContinuationsHolder(boolean createNew) {
+ //there is only one holder if continuations are not bound to session
+ if (!this.bindContinuationsToSession)
+ return this.continuationsHolder;
+
+ //if continuations bound to session lookup a proper holder in the session
+ Map objectModel = ContextHelper.getObjectModel(this.context);
+ Request request = ObjectModelHelper.getRequest(objectModel);
+
+ if (!createNew && request.getSession(false) == null)
+ return null;
+
+ Session session = request.getSession(true);
+ WebContinuationsHolder holder =
+ (WebContinuationsHolder) session.getAttribute(
+ WebContinuationsHolder.CONTINUATIONS_HOLDER);
+ if (!createNew)
+ return holder;
+
+ if (holder != null)
+ return holder;
+
+ holder = new WebContinuationsHolder();
+ session.setAttribute(WebContinuationsHolder.CONTINUATIONS_HOLDER,
+ holder);
+ return holder;
+ }
+
+ /**
+ * A holder for WebContinuations. When bound to session notifies the
+ * continuations manager of session invalidation.
+ */
+ public class WebContinuationsHolder implements HttpSessionBindingListener {
+ private final static String CONTINUATIONS_HOLDER =
+ "o.a.c.c.f.SCMI.WebContinuationsHolder";
+
+ private Map holder = Collections.synchronizedMap(new HashMap());
+
+ public WebContinuation get(Object id) {
+ return (WebContinuation) this.holder.get(id);
+ }
+
+ public void addContinuation(WebContinuation wk) {
+ this.holder.put(wk.getId(), wk);
+ }
+
+ public void removeContinuation(WebContinuation wk) {
+ this.holder.remove(wk.getId());
+ }
+
+ public Set getContinuationIds() {
+ return holder.keySet();
+ }
+
+ public boolean contains(String continuationId) {
+ return this.holder.containsKey(continuationId);
+ }
+
+ public boolean contains(WebContinuation wk) {
+ return contains(wk.getId());
+ }
+
+ public void valueBound(HttpSessionBindingEvent event) {
+ }
+
+ public void valueUnbound(HttpSessionBindingEvent event) {
+ invalidateContinuations(this);
+ }
+ }
+
+ /**
+ * WebContinuation extension that holds also the information about the
+ * holder. This information is needed to cleanup a proper holder after
+ * continuation's expiration time.
+ */
+ protected class HolderAwareWebContinuation extends WebContinuation {
+ private WebContinuationsHolder continuationsHolder;
+
+ public HolderAwareWebContinuation(String id, Object continuation,
+ WebContinuation parentContinuation, int timeToLive,
+ String interpreterId, ContinuationsDisposer disposer,
+ WebContinuationsHolder continuationsHolder) {
+ super(id, continuation, parentContinuation, timeToLive,
+ interpreterId, disposer);
+ this.continuationsHolder = continuationsHolder;
+ }
+
+ public WebContinuationsHolder getContinuationsHolder() {
+ return continuationsHolder;
+ }
+
+ //retain comparation logic from parent
+ public int compareTo(Object other) {
+ return super.compareTo(other);
+ }
+ }
+
+ public void contextualize(Context context) throws ContextException {
+ this.context = context;
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/ContinuationsManagerImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/FlowHelper.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/FlowHelper.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/FlowHelper.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/FlowHelper.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.apache.org/licenses/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.apache.cocoon.components.flow;
+
+import org.mozilla.javascript.Undefined;
+import org.mozilla.javascript.Wrapper;
+
+import java.util.Map;
+
+/**
+ * Provides the interface between the flow controller layer and the
+ * view layer. A view can obtain the context object sent by a flow
+ * script and the current web continuation, if any.
+ */
+public class FlowHelper {
+
+ // Constants defining keys in the object model used to store the various objects.
+ // These constants are private so that access to these objects only go through the
+ // accessors provided below.
+ //
+ // These objects are stored in the object model rather than as request attributes,
+ // as object model is cloned for subrequests (see EnvironmentWrapper), whereas
+ // request attributes are shared between the "real" request and all of its
+ // child requests.
+
+ /**
+ * Request attribute name used to store flow context.
+ */
+ private static final String CONTEXT_OBJECT = "cocoon.flow.context";
+
+ /**
+ * Request attribute name used to store flow continuation.
+ */
+ private static final String CONTINUATION_OBJECT = "cocoon.flow.continuation";
+
+ /**
+ * Get the flow context object associated with the current request
+ *
+ * @param objectModel The Cocoon Environment's object model
+ * @return The context object
+ */
+ public final static Object getContextObject(Map objectModel) {
+ return objectModel.get(CONTEXT_OBJECT);
+ }
+
+ /**
+ * Get the web continuation associated with the current request
+ *
+ * @param objectModel The Cocoon Environment's object model
+ * @return The web continuation
+ */
+ public final static WebContinuation getWebContinuation(Map objectModel) {
+ return (WebContinuation)objectModel.get(CONTINUATION_OBJECT);
+ }
+
+ /**
+ * Set the web continuation associated with the current request
+ *
+ * @param objectModel The Cocoon Environment's object model
+ * @param kont The web continuation
+ */
+ public final static void setWebContinuation(Map objectModel,
+ WebContinuation kont) {
+ objectModel.put(CONTINUATION_OBJECT, kont);
+ }
+
+ /**
+ * Set the flow context object associated with the current request
+ *
+ * @param objectModel The Cocoon Environment's object model
+ * @param obj The context object
+ */
+ public final static void setContextObject(Map objectModel, Object obj) {
+ objectModel.put(CONTEXT_OBJECT, obj);
+ }
+
+ /**
+ * Unwrap a Rhino object (getting the raw java object) and convert undefined to null
+ */
+ public static Object unwrap(Object obj) {
+ if (obj instanceof Wrapper) {
+ obj = ((Wrapper)obj).unwrap();
+ } else if (obj == Undefined.instance) {
+ obj = null;
+ }
+ return obj;
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/FlowHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/Interpreter.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/Interpreter.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/Interpreter.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/Interpreter.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,183 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.apache.org/licenses/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.apache.cocoon.components.flow;
+
+import org.apache.cocoon.environment.Redirector;
+
+import java.util.List;
+
+/**
+ * The interface to the flow scripting languages. This interface is
+ * for a component, which implements the appropriate language to be
+ * used for describing the flow. A system could have multiple
+ * components that implement this interface, each of them for a
+ * different scripting language.
+ *
+ * <p>A flow script defines what is the page flow in an interactive
+ * Web application. Usually the flow is defined in a high level
+ * programming language which provides the notion of continuations,
+ * which allows for the flow of the application to be described as a
+ * simple procedural program, without having to think about the
+ * application as a finite state machine which changes its internal
+ * state on each HTTP request from the client browser.
+ *
+ * <p>However an implementation may choose to use its own
+ * representation of an application, which may include XML
+ * representations of finite state machines. Note: this API has no
+ * provision for such implementations.
+ *
+ * <p>The component represented by this interface is called in three
+ * situations:
+ *
+ * <ul>
+ * <li>
+ * <p>From the sitemap, to invoke a top level function defined in a
+ * * given implementation language of the flow. This is done from
+ * the * sitemap using the construction:
+ *
+ * <pre>
+ * <map:call function="..." language="..."/>
+ * </pre>
+ *
+ * <p>The <code>language</code> attribute can be ignored if the *
+ * default language is used.
+ *
+ * <li>
+ * <p>From the sitemap, to continue a previously started
+ * computation. A previously started computation is saved in the
+ * form of a continuation inside the flow implementation language.
+ *
+ * <p>This case is similar with the above one, but the function
+ * invoked has a special name, specific to each language
+ * implementation. See the language implementation for more
+ * information on the function name and the arguments it receives.
+ *
+ * <li>
+ * <p>From a program in the flow layer. This is done to invoke a
+ * pipeline defined in the sitemap, to generate the response of the
+ * request.
+ * </ul>
+ *
+ * @author <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ * @since March 11, 2002
+ * @version CVS $Id: Interpreter.java 106091 2004-11-21 14:20:13Z lgawron $
+ */
+public interface Interpreter {
+
+ public static class Argument {
+ public String name;
+ public String value;
+
+ public Argument(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String toString() {
+ return name + ": " + value;
+ }
+ }
+
+ public static final String ROLE = Interpreter.class.getName();
+
+ /**
+ * @return the unique ID for this interpreter.
+ */
+ String getInterpreterID();
+
+ /**
+ * Set the unique ID for this interpreter.
+ */
+ void setInterpreterID(String interpreterID);
+
+ /**
+ * This method is called from the sitemap, using the syntax
+ *
+ * <pre>
+ * <map:call function="..."/>
+ * </pre>
+ *
+ * The method will execute the named function, which must be defined
+ * in the given language. There is no assumption made on how various
+ * arguments are passed to the function.
+ *
+ * <p>The <code>params</code> argument is a <code>List</code> object
+ * that contains <code>Interpreter.Argument</code> instances,
+ * representing the parameters to be passed to the called
+ * function. An <code>Argument</code> instance is a key-value pair,
+ * where the key is the name of the parameter, and the value is its
+ * desired value. Most languages will ignore the name value and
+ * simply pass to the function, in a positional order, the values of
+ * the argument. Some languages however can pass the arguments in a
+ * different order than the original prototype of the function. For
+ * these languages the ability to associate the actual argument with
+ * a formal parameter using its name is essential.
+ *
+ * <p>A particular language implementation may decide to put the
+ * environment, request, response etc. objects in the dynamic scope
+ * available to the function at the time of the call. Other
+ * implementations may decide to pass these as arguments to the
+ * called function.
+ *
+ * <p>The current implementation assumes the sitemap implementation
+ * is TreeProcessor.
+ *
+ * @param funName a <code>String</code> value, the name of the
+ * function to call
+ * @param params a <code>List</code> object whose components are
+ * CallFunctionNode.Argument instances. The interpretation of the
+ * parameters is left to the actual implementation of the
+ * interpreter.
+ * @param redirector a <code>Redirector</code> used to call views
+ */
+ void callFunction(String funName, List params, Redirector redirector)
+ throws Exception;
+
+ /**
+ * Forward the request to a Cocoon pipeline.
+ *
+ * @param uri a <code>String</code>, the URI of the forwarded request
+ * @param bizData an <code>Object</code>, the business data object
+ * to be made available to the forwarded pipeline
+ * @param continuation a <code>WebContinuation</code>, the
+ * continuation to be called to resume the processing
+ * @param redirector a <code>Redirector</code> used to call views
+ * @exception Exception if an error occurs
+ */
+ void forwardTo(String uri, Object bizData, WebContinuation continuation,
+ Redirector redirector)
+ throws Exception;
+
+ /**
+ * Continues a previously started processing. The continuation
+ * object where the processing should start from is indicated by the
+ * <code>continuationId</code> string.
+ *
+ * @param continuationId a <code>String</code> value
+ *
+ * @param params a <code>List</code> value, containing the
+ * parameters to be passed when invoking the continuation. As
+ * opposed to the parameters passed by <code>callFunction</code>,
+ * these parameters will only become available in the language's
+ * environment, if at all.
+ *
+ * @param redirector a <code>Redirector</code> used to call views
+ * @exception Exception if an error occurs
+ */
+ void handleContinuation(String continuationId, List params,
+ Redirector redirector)
+ throws Exception;
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/Interpreter.java
------------------------------------------------------------------------------
svn:eol-style = native