You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by mr...@apache.org on 2005/08/26 07:46:58 UTC

svn commit: r240168 [21/30] - in /struts/sandbox/trunk/ti: ./ core/src/java/org/apache/ti/ core/src/java/org/apache/ti/config/ core/src/java/org/apache/ti/config/mapper/ core/src/java/org/apache/ti/core/ core/src/java/org/apache/ti/core/factory/ core/s...

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ArrayIndexToken.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ArrayIndexToken.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ArrayIndexToken.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ArrayIndexToken.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,70 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.script.el.tokens;
+
+import org.apache.ti.util.logging.Logger;
+
+import java.util.List;
+
+/**
+ *
+ */
+public class ArrayIndexToken
+        extends ExpressionToken {
+
+    private static final Logger LOGGER = Logger.getInstance(ArrayIndexToken.class);
+
+    private int _index;
+
+    public ArrayIndexToken(String identifier) {
+        _index = Integer.parseInt(identifier);
+    }
+
+    public void update(Object root, Object newValue) {
+        if (root instanceof List)
+            listUpdate((List) root, _index, newValue);
+        else if (root.getClass().isArray())
+            arrayUpdate(root, _index, newValue);
+        else {
+            RuntimeException re = new RuntimeException("The _index \"" + _index + "\" can not be used to look-up the type of a property" +
+                    " on an object that is not an array or list.");
+            LOGGER.error("", re);
+            throw re;
+        }
+    }
+
+    public Object evaluate(Object value) {
+        if (value instanceof List)
+            return listLookup((List) value, _index);
+        else if (value.getClass().isArray())
+            return arrayLookup(value, _index);
+        else {
+            RuntimeException re = new RuntimeException("The _index \"" + _index + "\" can not be used to look-up a property on an object that is not an array or list.");
+            LOGGER.error("", re);
+            throw re;
+        }
+    }
+
+    public String getTokenString() {
+        return "[" + _index + "]";
+    }
+
+    public String toString() {
+        return "" + _index;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ContextToken.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ContextToken.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ContextToken.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ContextToken.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,47 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.script.el.tokens;
+
+public class ContextToken
+        extends ExpressionToken {
+
+    private String _context = null;
+
+    public ContextToken(String context) {
+        _context = context;
+    }
+
+    public void update(Object value, Object newValue) {
+    }
+
+    public String getName() {
+        return _context;
+    }
+
+    public Object evaluate(Object value) {
+        return null;
+    }
+
+    public String getTokenString() {
+        return _context;
+    }
+
+    public String toString() {
+        return _context;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ExpressionToken.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ExpressionToken.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ExpressionToken.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/ExpressionToken.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,225 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.script.el.tokens;
+
+import org.apache.ti.script.el.util.ParseUtils;
+import org.apache.ti.util.internal.cache.PropertyCache;
+import org.apache.ti.util.logging.Logger;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public abstract class ExpressionToken {
+
+    private static final Logger LOGGER = Logger.getInstance(ArrayIndexToken.class);
+
+    private static final PropertyCache PROPERTY_CACHE = new PropertyCache();
+
+    public abstract Object evaluate(Object value);
+
+    public abstract void update(Object root, Object newValue);
+
+    public abstract String getTokenString();
+
+
+    /*
+     *
+     * Property Lookup
+     *
+     */
+    protected final Object mapLookup(Map map, Object identifier) {
+        if (LOGGER.isDebugEnabled())
+            LOGGER.debug("mapLookup: " + identifier);
+        return map.get(identifier);
+    }
+
+    protected final Object beanLookup(Object bean, Object identifier) {
+        if (LOGGER.isDebugEnabled())
+            LOGGER.debug("beanLookup: " + identifier);
+
+        return ParseUtils.getProperty(bean, identifier.toString(), PROPERTY_CACHE);
+    }
+
+    protected final Object listLookup(List list, int index) {
+        if (LOGGER.isDebugEnabled())
+            LOGGER.debug("listLookup: " + index);
+
+        return list.get(index);
+    }
+
+    protected final Object arrayLookup(Object array, int index) {
+        if (LOGGER.isDebugEnabled())
+            LOGGER.debug("arrayLookup: " + index);
+
+        return Array.get(array, index);
+    }
+
+    protected final void mapUpdate(Map map, Object identifier, Object value) {
+        Object converted = value;
+
+        Object o = map.get(identifier);
+        if (o != null) {
+            Class type = o.getClass();
+            value = ParseUtils.convertType(value, type);
+        }
+
+        map.put(identifier, value);
+    }
+
+    protected final void arrayUpdate(Object array, int index, Object value) {
+        Object converted = value;
+
+        Class elementType = array.getClass().getComponentType();
+        if (!elementType.isAssignableFrom(value.getClass())) {
+            converted = ParseUtils.convertType(value, elementType);
+        }
+
+        try {
+            Array.set(array, index, converted);
+        } catch (Exception e) {
+            String msg = "An error occurred setting a value at index \"" + index + "\" on an array with component types \"" +
+                    elementType + "\".  Cause: " + e.toString();
+
+            if (LOGGER.isErrorEnabled()) LOGGER.error(msg);
+            throw new RuntimeException(msg);
+        }
+    }
+
+    protected final void listUpdate(List list, int index, Object value) {
+        Object converted = value;
+
+        if (list.size() > index) {
+            Object o = list.get(index);
+            // can only convert types when there is an item in the currently requested place
+            if (o != null) {
+                Class itemType = o.getClass();
+                converted = ParseUtils.convertType(value, itemType);
+            }
+
+            list.set(index, value);
+        } else {
+            // @note: not sure that this is the right thing.  Question is whether or not to insert nulls here to fill list up to "index"
+            // @update: List doesn't guarantee that implementations will accept nulls.  So, we can't rely on that as a solution.
+            // @update: this is an unfortunate but necessary solution...unless the List has enough elements to 
+            // accomodate the new item at a particular index, this must be an error case.  The reasons are this:
+            // 1) can't fill the list with nulls, List implementations are allowed to disallow them
+            // 2) can't just do an "add" to the list -- in processing [0] and [1] on an empty list, [1] may get processed first. 
+            //    this will go into list slot [0].  then, [0] gets processed and simply overwrites the previous because it's 
+            //    already in the list
+            // 3) can't go to a mixed approach because there's no metadata about what has been done and no time to build
+            //    something that is apt to be complicated and exposed to the user
+            // so...
+            // the ultimate 8.1sp2 functionality is to simply disallow updating a value in a list that doesn't exist.  that 
+            // being said, it is still possible to simply add to the list.  if {actionForm.list[42]} inserts into the 42'nd 
+            // item, {actionForm.list} will just do an append on POST since there is no index specified.  this fix does 
+            // not break backwards compatability because it will work on full lists and is completely broken now on empty 
+            // lists, so changing this just gives a better exception message that "ArrayIndexOutOfBounds".  :)
+            // 
+            // September 2, 2003
+            // ekoneil@bea.com
+            // 
+            String msg = "An error occurred setting a value at index \"" + index + "\" because the list is " +
+                    (list != null ? (" of size " + list.size()) : "null") + ".  " +
+                    "Be sure to allocate enough items in the List to accomodate any updates which may occur against the list.";
+
+            if (LOGGER.isErrorEnabled()) LOGGER.error(msg);
+
+            throw new RuntimeException(msg);
+        }
+    }
+
+    protected final void beanUpdate(Object bean, Object identifier, Object value) {
+        if (LOGGER.isDebugEnabled()) LOGGER.debug("Update \"" + bean + "\" type property \"" + identifier + "\"");
+
+        String id = identifier.toString();
+        Class beanType = bean.getClass();
+        Class propType = PROPERTY_CACHE.getPropertyType(beanType, id);
+        if (propType != null) {
+            try {
+                if (java.util.List.class.isAssignableFrom(propType)) {
+                    Method lm = PROPERTY_CACHE.getPropertyGetter(beanType, id);
+                    if (lm != null) {
+                        List list = (List) lm.invoke(bean, (Object[]) null);
+                        applyValuesToList(value, list);
+                        return;
+                    }
+                } else {
+                    Method m = PROPERTY_CACHE.getPropertySetter(beanType, id);
+
+                    if (m != null) {
+                        if (LOGGER.isDebugEnabled())
+                            LOGGER.debug("Apply value to property via method: " + m);
+
+                        Class targetType = m.getParameterTypes()[0];
+                        Object converted = ParseUtils.convertType(value, targetType);
+
+                        m.invoke(bean, new Object[]{converted});
+                        return;
+                    }
+                }
+            } catch (Exception e) {
+                String msg = "Could not update proprety named \"" + id + "\" on bean of type \"" + beanType + "\".  Cause: " + e;
+                if (LOGGER.isErrorEnabled())
+                    LOGGER.error(msg, e);
+                throw new RuntimeException(msg, e);
+            }
+        }
+
+        String msg = "Could not update expression because a public JavaBean setter for the property \"" + identifier + "\" could not be found.";
+        LOGGER.error(msg);
+        throw new RuntimeException(msg);
+    }
+
+    protected final int parseIndex(String identifier) {
+        try {
+            return Integer.parseInt(identifier);
+        } catch (Exception e) {
+            String msg = "Error performing an array look-up with the index \"" + identifier + "\". Cause: " + e;
+
+            if (LOGGER.isDebugEnabled())
+                LOGGER.debug(msg, e);
+
+            throw new RuntimeException(msg, e);
+        }
+    }
+
+    private static final void applyValuesToList(Object value, List list) {
+        if (list == null) {
+            String msg = "Can not add a value to a null java.util.List";
+            LOGGER.error(msg);
+            throw new RuntimeException(msg);
+        }
+
+        if (value instanceof String[]) {
+            String[] ary = (String[]) value;
+            for (int i = 0; i < ary.length; i++) {
+                list.add(ary[i]);
+            }
+        } else if (value instanceof String) {
+            list.add(value);
+        }
+        // types that are not String[] or String are just set on the object
+        else
+            list.add(value);
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/IdentifierToken.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/IdentifierToken.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/IdentifierToken.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/IdentifierToken.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,97 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.script.el.tokens;
+
+import org.apache.ti.util.logging.Logger;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class IdentifierToken
+        extends ExpressionToken {
+
+    private static final Logger LOGGER = Logger.getInstance(IdentifierToken.class);
+    private static final boolean DEBUG_ENABLED = LOGGER.isDebugEnabled();
+
+    private String _identifier = null;
+
+    public IdentifierToken(String identifier) {
+        _identifier = identifier;
+    }
+
+    public Object evaluate(Object value) {
+        /* todo: error handling */
+        if (value == null) {
+            String msg = "Can not evaluate the identifier \"" + _identifier + "\" on a null value object.";
+            if (LOGGER.isErrorEnabled())
+                LOGGER.error(msg);
+            throw new RuntimeException(msg);
+        }
+
+        if (DEBUG_ENABLED) {
+            LOGGER.debug("evaluate: " + _identifier);
+            LOGGER.debug("value type: " + value.getClass().getName());
+        }
+
+        if (value instanceof Map) {
+            return mapLookup((Map) value, _identifier);
+        } else if (value instanceof List) {
+            int i = parseIndex(_identifier);
+            return listLookup((List) value, i);
+        } else if (value.getClass().isArray()) {
+            int i = parseIndex(_identifier);
+            return arrayLookup(value, i);
+        } else
+            return beanLookup(value, _identifier);
+    }
+
+    public void update(Object root, Object newValue) {
+        /* todo: error handling */
+        if (root == null) {
+            String msg = "Can not update the identifier \"" + _identifier + "\" on a null value object.";
+            if (LOGGER.isErrorEnabled())
+                LOGGER.error(msg);
+            throw new RuntimeException(msg);
+        }
+
+        if (DEBUG_ENABLED)
+            LOGGER.debug("Update _identifier \"" + _identifier + "\" on object of type: \"" + root.getClass().getName() + "\"");
+
+        if (root instanceof Map)
+            mapUpdate((Map) root, _identifier, newValue);
+        else if (root instanceof List) {
+            int i = parseIndex(_identifier);
+            listUpdate((List) root, i, newValue);
+        } else if (root.getClass().isArray()) {
+            int i = parseIndex(_identifier);
+            arrayUpdate(root, i, newValue);
+        } else
+            beanUpdate(root, _identifier, newValue);
+    }
+
+    public String getTokenString() {
+        return "." + _identifier;
+    }
+
+    public String toString() {
+        return _identifier;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/MapKeyToken.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/MapKeyToken.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/MapKeyToken.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/tokens/MapKeyToken.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,113 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.script.el.tokens;
+
+import org.apache.ti.util.internal.InternalStringBuilder;
+import org.apache.ti.util.logging.Logger;
+
+import java.util.Map;
+
+/**
+ *
+ */
+public class MapKeyToken
+        extends ExpressionToken {
+
+    private static final Logger LOGGER = Logger.getInstance(MapKeyToken.class);
+
+    private String _identifier = null;
+    private boolean _dblQuote = false;
+
+    public MapKeyToken(String identifier) {
+        this._identifier = identifier;
+
+        if (identifier.startsWith("\""))
+            _dblQuote = true;
+
+        // convert the Java string to an EcmaScript string.  Strip the quotes that exist because they're
+        // always there for this token.
+        this._identifier = convertToEcmaScriptString(this._identifier.substring(1, identifier.length() - 1));
+    }
+
+    /**
+     * Given a Java String, this value needs to be converted into a JavaScript compliant String.
+     * See JavaScript: The Definitive Guide for how to do this
+     */
+    private final String convertToEcmaScriptString(String string) {
+        CharSequence cs = string;
+
+        int len = cs.length();
+        InternalStringBuilder buf = new InternalStringBuilder(len);
+        for (int i = 0; i < len; i++) {
+            char c = cs.charAt(i);
+            // skip the \\ and consume the next character either appending it or turning it back into the single character
+            // that it should have been in the first place.
+            // 
+            // if slash and not at the last character...
+            if (c == '\\' && i + 1 < len) {
+                i++;
+
+                // skip the slash
+                c = cs.charAt(i);
+
+                if (c == 'b')
+                    c = '\b';
+                else if (c == 't')
+                    c = '\t';
+                else if (c == 'n')
+                    c = '\n';
+                //else if(c == 'v') c = '\v';
+                else if (c == 'f')
+                    c = '\f';
+                else if (c == 'r') c = '\r';
+                // @TODO: unicode escaping...
+            }
+
+            buf.append(c);
+        }
+
+        if (LOGGER.isDebugEnabled()) LOGGER.debug("new _identifier: " + buf.toString());
+
+        return buf.toString();
+    }
+
+    public void update(Object root, Object newValue) {
+        if (root instanceof Map)
+            mapUpdate((Map) root, _identifier, newValue);
+        else
+            beanUpdate(root, _identifier, newValue);
+    }
+
+    public Object evaluate(Object value) {
+        if (value instanceof Map)
+            return mapLookup((Map) value, _identifier);
+        else
+            return beanLookup(value, _identifier);
+    }
+
+    public String getTokenString() {
+        if (_dblQuote)
+            return "[\"" + _identifier + "\"]";
+        else
+            return "['" + _identifier + "']";
+    }
+
+    public String toString() {
+        return _identifier;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/AbstractAttributeMap.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/AbstractAttributeMap.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/AbstractAttributeMap.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/AbstractAttributeMap.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,106 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.script.el.util;
+
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ */
+public abstract class AbstractAttributeMap
+        implements Map {
+
+    private Map _map = null;
+
+    protected abstract Object getValue(Object key);
+
+    protected abstract Object putValue(Object key, Object value);
+
+    protected abstract Enumeration getKeysEnumeration();
+
+    public void clear() {
+    }
+
+    public boolean containsKey(Object key) {
+        return (getValue(key) != null);
+    }
+
+    public boolean containsValue(Object key) {
+        return getMap().containsValue(key);
+    }
+
+    public Set entrySet() {
+        return getMap().entrySet();
+    }
+
+    public Object get(Object key) {
+        return getValue(key);
+    }
+
+    public boolean isEmpty() {
+        return getMap().isEmpty();
+    }
+
+    public Set keySet() {
+        return getMap().keySet();
+    }
+
+    public Object put(Object key, Object value) {
+        return putValue(key, value);
+    }
+
+    public void putAll(Map t) {
+        getMap().putAll(t);
+    }
+
+    public Object remove(Object key) {
+        return getMap().remove(key);
+    }
+
+    public int size() {
+        return getMap().size();
+    }
+
+    public Collection values() {
+        return getMap().values();
+    }
+
+    private Map getMap() {
+        if (_map == null)
+            _map = convertToMap();
+
+        return _map;
+    }
+
+    private Map convertToMap() {
+        if (_map == null)
+            _map = new HashMap();
+
+        Enumeration keys = getKeysEnumeration();
+        while (keys.hasMoreElements()) {
+            Object key = keys.nextElement();
+            _map.put(key, getValue(key));
+        }
+
+        return _map;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/BindingContext.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/BindingContext.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/BindingContext.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/BindingContext.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,26 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.script.el.util;
+
+/**
+ *
+ */
+public interface BindingContext {
+
+    public Object unwrap();
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/ParseUtils.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/ParseUtils.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/ParseUtils.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/script/el/util/ParseUtils.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,222 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.script.el.util;
+
+import org.apache.ti.script.el.ExpressionParseException;
+import org.apache.ti.script.el.NetUIVariableResolver;
+import org.apache.ti.script.el.ParsedExpression;
+import org.apache.ti.script.el.parser.NetUIELParser;
+import org.apache.ti.script.el.parser.ParseException;
+import org.apache.ti.script.el.parser.TokenMgrError;
+import org.apache.ti.util.internal.InternalStringBuilder;
+import org.apache.ti.util.internal.cache.PropertyCache;
+import org.apache.ti.util.logging.Logger;
+import org.apache.ti.util.type.TypeUtils;
+
+import java.io.StringReader;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+/**
+ *
+ */
+public class ParseUtils {
+
+    private static final Logger LOGGER = Logger.getInstance(ParseUtils.class);
+
+    private static final HashMap/*<String, ParsedExpression>*/ PARSED_CACHE = new HashMap/*<String, ParsedExpression>*/();
+
+    /* do not construct */
+    private ParseUtils() {
+    }
+
+    public static final ParsedExpression parse(String exprStr) {
+        ParsedExpression pe = (ParsedExpression) PARSED_CACHE.get(exprStr);
+
+        if (pe != null)
+            return pe;
+
+        try {
+            NetUIELParser learn = new NetUIELParser(new StringReader(exprStr));
+
+            ParsedExpression expr = learn.parse();
+            expr.seal();
+
+            /* infrequent; this should only happen when there is a cache miss */
+            synchronized (PARSED_CACHE) {
+                PARSED_CACHE.put(exprStr, expr);
+            }
+
+            return expr;
+        } catch (ParseException e) {
+            String msg = "Error occurred parsing expression \"" + exprStr + "\".";
+            LOGGER.error(msg, e);
+            throw new ExpressionParseException(msg, e);
+        } catch (TokenMgrError tm) {
+            String msg = "Error occurred parsing expression \"" + exprStr + "\".";
+            LOGGER.error(msg, tm);
+            throw new ExpressionParseException(msg, tm);
+        }
+    }
+
+    public static final Object evaluate(String exprStr, NetUIVariableResolver vr) {
+        ParsedExpression expr = parse(exprStr);
+        assert expr != null;
+        return expr.evaluate(vr);
+    }
+
+    public static final void update(String exprStr, Object value, NetUIVariableResolver vr) {
+        ParsedExpression expr = parse(exprStr);
+        assert expr != null;
+        expr.update(value, vr);
+    }
+
+    public static final Class getPropertyType(Object value, String name, PropertyCache cache) {
+        assert value != null;
+        assert cache != null;
+
+        Class type = value.getClass();
+
+        Method m = cache.getPropertySetter(type, name);
+        if (m == null) {
+            String msg = "Can not find setter method for property \"" + name + "\" on object of type \"" + value.getClass() + "\".";
+            LOGGER.error(msg);
+            throw new RuntimeException(msg);
+        }
+        // PropertyCache guarantees that props are found and match JavaBean naming rules
+        else {
+            assert m.getParameterTypes().length == 1;
+            return m.getParameterTypes()[0];
+        }
+    }
+
+    public static final Object getProperty(Object value, String name, PropertyCache cache) {
+        assert value != null;
+        assert cache != null;
+
+        Class type = value.getClass();
+
+        Method m = cache.getPropertyGetter(type, name);
+        if (m != null) {
+            try {
+                return m.invoke(value, (Object[]) null);
+            } catch (Exception e) {
+                String msg = "An error occurred invoking a getter for the property  \"" + name + "\" on an object of type \"" + type + "\".";
+                LOGGER.error(msg, e);
+                throw new RuntimeException(msg, e);
+            }
+        }
+
+        String msg = "Could not find JavaBean property named \"" + name + "\" on object of type \"" + type + "\"";
+        LOGGER.error(msg);
+        throw new RuntimeException(msg);
+    }
+
+    public static final Object convertType(Object value, Class toType) {
+        assert toType != null;
+
+        try {
+            boolean sourceIsArray = false;
+
+            /* only convert String types; other Object types are already assumed to be in their target types. */
+            if (value != null && !(value instanceof String || (sourceIsArray = (value instanceof String[]))))
+                return value;
+
+            /* for a String[], convert each item in the array into its target type and return the resulting array. */
+            if (toType.isArray()) {
+                if (value == null)
+                    return null;
+                else {
+                    Class compType = toType.getComponentType();
+
+                    String[] strs = null;
+                    if (value.getClass().isArray())
+                        strs = (String[]) value;
+                    else
+                        strs = new String[]{(String) value};
+
+                    Object tgt = Array.newInstance(compType, strs.length);
+
+                    for (int i = 0; i < strs.length; i++) {
+                        Object o = null;
+                        try {
+                            /* todo: support getting the Locale here in an ExpressionContext object */
+                            o = TypeUtils.convertToObject(strs[i], compType);
+                        } catch (IllegalArgumentException e) {
+                            String msg = "Can not set Object types via expressions that are not supported by the set of registered type converters.  Cause: " + e;
+                            LOGGER.error(msg, e);
+                            throw new RuntimeException(msg, e);
+                        }
+
+                        Array.set(tgt, i, o);
+                    }
+
+                    return tgt;
+                }
+            }
+            // convert the String into its target type and return the result
+            else {
+                // If the "value" is multi-valued (String[]), it needs to be converted into a single-valued object.
+                // There is no policy defined for how we do this right now, so the first one will always win when 
+                // multiple expressions reference the same property.  When that property is a String type, the result
+                // is an HttpServletRequest that contains a String[], and here, we'll always the String[0].
+                if (sourceIsArray) {
+                    assert value instanceof String[];
+                    assert Array.getLength(value) > 0 && Array.getLength(value) - 1 >= 0;
+
+                    value = Array.get(value, Array.getLength(value) - 1);
+                }
+
+                try {
+                    assert value == null || value instanceof String;
+
+                    return TypeUtils.convertToObject((String) value, toType);
+                } catch (IllegalArgumentException e) {
+                    String msg = "The type \"" + toType.getName() + "\" can not be set through the NetUI expression language.";
+                    LOGGER.error(msg, e);
+                    throw new RuntimeException(msg, e);
+                }
+            }
+        } catch (Exception e) {
+            String msg = "Unable to convert a value of type \"" + value.getClass() + "\" to the array element type of \"" + toType + "\".  Cause: " + e;
+            LOGGER.error(msg, e);
+            throw new RuntimeException(msg, e);
+        }
+    }
+
+    public static String getContextString(String[] contexts) {
+        InternalStringBuilder builder = new InternalStringBuilder();
+        builder.append("[");
+        if (contexts != null) {
+            for (int i = 0; i < contexts.length; i++) {
+                if (i > 0) builder.append(", ");
+                builder.append(contexts[i]);
+            }
+        }
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public static Throwable getRootCause(Throwable t) {
+        Throwable root = t;
+        while (root.getCause() != null)
+            root = root.getCause();
+        return root;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowFacesFilter.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowFacesFilter.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowFacesFilter.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowFacesFilter.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,46 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.servlet;
+
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.servlet.PageFlowPageFilter;
+import org.apache.ti.servlet.PageFlowPageFilter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+
+/**
+ * Servlet Filter for JavaServer Faces requests.
+ */ 
+public class PageFlowFacesFilter
+        extends PageFlowPageFilter
+{
+    private static Set/*< String >*/ VALID_FILE_EXTENSIONS = new HashSet/*< String >*/();
+    
+    static
+    {
+        VALID_FILE_EXTENSIONS.add( InternalConstants.FACES_EXTENSION );
+        VALID_FILE_EXTENSIONS.add( InternalConstants.JSF_EXTENSION );
+    }
+    
+    protected Set getValidFileExtensions()
+    {
+        return VALID_FILE_EXTENSIONS;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowForbiddenFilter.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowForbiddenFilter.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowForbiddenFilter.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowForbiddenFilter.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,86 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.servlet;
+
+import org.apache.ti.util.logging.Logger;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.FilterChain;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+
+/**
+ * Servlet Filter that sends a specified error code on the response.  Used to prevent Java source from being displayed
+ * in the browser, in the case where it is mixed in with web content, and the web content directory itself is being
+ * deployed.
+ */ 
+public class PageFlowForbiddenFilter
+        implements Filter
+{
+    private static final Logger _log = Logger.getInstance( PageFlowForbiddenFilter.class );
+    private static final int DEFAULT_RESPONSE_CODE = HttpServletResponse.SC_FORBIDDEN;
+    
+    private int _responseCode = DEFAULT_RESPONSE_CODE;
+    
+    public void init( FilterConfig filterConfig ) throws ServletException
+    {
+        String responseCodeStr = filterConfig.getInitParameter( "response-code" );
+        
+        if ( responseCodeStr != null )
+        {
+            try
+            {
+                _responseCode = Integer.parseInt( responseCodeStr );
+            }
+            catch ( NumberFormatException e )
+            {
+                _log.error( "Could not parse response-code \"" + responseCodeStr + "\" for Servlet Filter "
+                            + PageFlowForbiddenFilter.class.getName(), e );
+            }
+        }
+    }
+
+    public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain )
+            throws IOException, ServletException
+    {
+        if ( ! ( servletResponse instanceof HttpServletResponse ) )
+        {
+            _log.error( "Servlet Filter " + PageFlowForbiddenFilter.class.getName() + " used against a non-HTTP response: "
+                        + servletResponse.getClass().getName() );
+            return;
+        }
+        
+        if ( _log.isInfoEnabled() )
+        {
+            _log.info( "Request for " + ( ( HttpServletRequest ) servletRequest ).getServletPath() + " handled by "
+                       + PageFlowForbiddenFilter.class.getName() );
+        }
+        
+        ( ( HttpServletResponse ) servletResponse ).sendError( _responseCode );
+    }
+
+    public void destroy()
+    {
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowJspFilter.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowJspFilter.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowJspFilter.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowJspFilter.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.servlet;
+
+import org.apache.ti.servlet.PageFlowPageFilter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+
+/**
+ * Servlet Filter for JSP requests.
+ */ 
+public class PageFlowJspFilter
+        extends PageFlowPageFilter
+{
+    private static Set/*< String >*/ VALID_FILE_EXTENSIONS = new HashSet/*< String >*/();
+    
+    static
+    {
+        VALID_FILE_EXTENSIONS.add( "jsp" );
+        VALID_FILE_EXTENSIONS.add( "jspx" );
+    }
+    
+    protected Set getValidFileExtensions()
+    {
+        return VALID_FILE_EXTENSIONS;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowPageFilter.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowPageFilter.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowPageFilter.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/PageFlowPageFilter.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,164 @@
+/*
+* Copyright 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.
+*
+* $Header:$
+*/
+package org.apache.ti.servlet;
+
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.pageflow.PageFlowException;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+import org.apache.ti.util.internal.FileUtils;
+import org.apache.ti.util.internal.ServletUtils;
+import org.apache.ti.util.logging.Logger;
+import org.apache.ti.processor.chain.pageflow.ShowView;
+import org.apache.ti.processor.RequestProcessor;
+import org.apache.commons.chain.web.WebContext;
+import org.apache.commons.chain.web.servlet.ServletWebContext;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Set;
+
+
+/**
+ * Base class for Servlet Filters that run before Page Flow page requests.
+ */ 
+public abstract class PageFlowPageFilter implements Filter
+{
+    private static final Logger _log = Logger.getInstance( PageFlowPageFilter.class );
+    private static final String PREVENT_CACHE_ATTR = InternalConstants.ATTR_PREFIX + "preventCache";
+    
+    private RequestProcessor _requestProcessor;
+    private ServletContext _servletContext;
+    
+    
+    protected PageFlowPageFilter()
+    {
+    }
+    
+    public void init( FilterConfig filterConfig ) throws ServletException
+    {
+        _servletContext = filterConfig.getServletContext();
+        ServletConfiguration servletConfiguration = ServletConfiguration.init(_servletContext);
+        _requestProcessor = servletConfiguration.createRequestProcessor(_servletContext, "viewRequestProcessor", null);
+    }
+    
+    protected abstract Set getValidFileExtensions();
+    
+    public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain )
+            throws IOException, ServletException
+    {
+        if ( request instanceof HttpServletRequest && response instanceof HttpServletResponse )
+        {
+            HttpServletRequest httpRequest = ( HttpServletRequest ) request;
+            HttpServletResponse httpResponse = ( HttpServletResponse ) response;
+            
+            //
+            // Don't do the filter if the request is in error.
+            //
+            Object errStatusCode = request.getAttribute( "javax.servlet.error.status_code" );
+            if ( errStatusCode != null )
+            {
+                if ( _log.isDebugEnabled() )
+                {
+                    _log.debug( "Request has error status code " + errStatusCode + ".  Skipping filter." );
+                }
+                
+                chain.doFilter(request, response);
+                return;           
+            }
+            
+            //
+            // If at an earlier stage in the request we determined that we should prevent caching,
+            // actually write the appropriate headers to the response now.
+            //
+            if ( request.getAttribute( PREVENT_CACHE_ATTR ) != null ) ServletUtils.preventCache( httpResponse );
+            
+            String servletPath = httpRequest.getServletPath();
+            String extension = FileUtils.getFileExtension( servletPath );
+            Set validFileExtensions = getValidFileExtensions();
+            
+            if ( validFileExtensions != null && ! validFileExtensions.contains( extension ) )
+            {
+                if ( _log.isDebugEnabled() )
+                {
+                    _log.debug( "Path " + servletPath +
+                                " does not have an appropriate file extension.  Skipping filter." );
+                }
+                
+                chain.doFilter( request, response );
+                return;
+            }
+            
+            if ( _log.isDebugEnabled() ) _log.debug( "Filtering request for path " + servletPath );
+            
+            FilterChainViewRunner viewRunner = new FilterChainViewRunner(chain);
+            viewRunner.activate();
+            _requestProcessor.process(new ServletWebContext(_servletContext, httpRequest, httpResponse));
+        }
+        else
+        {
+            chain.doFilter( request, response );
+        }
+    }
+    
+    private static class FilterChainViewRunner extends ShowView.ViewRunner {
+        
+        private FilterChain _chain;
+        
+        public FilterChainViewRunner(FilterChain chain) {
+            _chain = chain;
+        }
+        
+        public void runView() throws PageFlowException {
+            WebContext webContext = PageFlowActionContext.get().getWebContext();
+            assert webContext instanceof ServletWebContext : webContext.getClass().getName();
+            ServletWebContext servletWebContext = (ServletWebContext) webContext;
+            
+            try {
+                _chain.doFilter(servletWebContext.getRequest(), servletWebContext.getResponse());
+            } catch (ServletException e ) {
+                throw new PageFlowException(e);
+            } catch (IOException e ) {
+                throw new PageFlowException(e);
+            }
+        }
+    }
+    
+    /**
+     * Make sure that when this page is rendered, it will set headers in the response to prevent caching.
+     * Because these headers are lost on server forwards, we set a request attribute to cause the headers
+     * to be set right before the page is rendered.
+     */ 
+    static void preventCache( HttpServletRequest request )
+    {
+        request.setAttribute( PREVENT_CACHE_ATTR, Boolean.TRUE );
+    }
+    
+    public void destroy()
+    {
+        _requestProcessor.destroy();
+        _requestProcessor = null;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/ServletConfiguration.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/ServletConfiguration.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/ServletConfiguration.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/ServletConfiguration.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,161 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.servlet;
+
+import org.springframework.beans.factory.xml.XmlBeanFactory;
+import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.core.io.UrlResource;
+import org.apache.ti.util.ServletSourceResolver;
+import org.apache.ti.processor.RequestProcessor;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.chain.web.servlet.ServletWebContext;
+
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.ServletContext;
+import java.net.URL;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+// This class is package-protected -- only exposed to our Servlet/Filters for now.
+/**
+ * Manages config (Spring and Properties) for Ti Servlets/Filters
+ */ 
+class ServletConfiguration {
+    
+    private static Log log = LogFactory.getLog(ServletConfiguration.class);
+    private static final String CONFIG_KEY = "ti.servletConfig";
+    
+    protected String springConfig = "org/apache/ti/config/spring-config-servlet.xml";
+    protected BeanFactory beanFactory = null;
+    protected Properties tiProps = new Properties();
+    protected String tiConfig = "ti.properties";
+    protected String tiDefaultsConfig = "ti-defaults.properties";
+    
+    
+    public static ServletConfiguration init(ServletContext servletContext) throws ServletException {
+        ServletConfiguration servletConfiguration = (ServletConfiguration) servletContext.getAttribute(CONFIG_KEY);
+        if (servletConfiguration == null) {
+            servletConfiguration = new ServletConfiguration(servletContext);
+            servletContext.setAttribute(CONFIG_KEY, servletConfiguration);
+        }
+        return servletConfiguration;
+    }
+    
+    public static ServletConfiguration get(ServletContext servletContext) {
+        ServletConfiguration servletConfiguration = (ServletConfiguration) servletContext.getAttribute(CONFIG_KEY);
+        assert servletConfiguration != null : "ServletConfiguration not found in context under attr " + CONFIG_KEY;
+        return servletConfiguration;
+    }
+
+    public RequestProcessor createRequestProcessor(ServletContext servletContext, String processorName, Map params) {
+        Map initParameters = new HashMap();
+        if (params != null) {
+            initParameters.putAll(params);
+        }
+        RequestProcessor processor = (RequestProcessor) beanFactory.getBean(processorName);
+        processor.init(initParameters, new ServletWebContext(servletContext, null, null)); 
+        return processor;
+    }
+    
+    protected ServletConfiguration(ServletContext servletContext) throws ServletException {
+        initProperties(servletContext);
+        initSpring(servletContext);
+    }
+    
+    protected void initProperties(ServletContext servletContext) throws ServletException {
+        String s = servletContext.getInitParameter("tiConfig");
+        if (s != null) {
+            tiConfig = s;
+        }    
+        try {
+            // First, load defaults
+            URL tiDefaultsConfigURL = ServletSourceResolver.resolve(tiDefaultsConfig, true, servletContext);
+            tiProps.load(tiDefaultsConfigURL.openStream());
+
+            // Next, load from web.xml
+            String key;
+            for (Enumeration e = servletContext.getInitParameterNames(); e.hasMoreElements();) {
+                key = (String) e.nextElement();
+                tiProps.put("ti."+key, servletContext.getInitParameter(key));
+            }
+            
+            // Finally, load from user's properties file 
+            URL resource = ServletSourceResolver.resolve(tiConfig, false, servletContext);
+            if (resource != null) {
+                tiProps.load(resource.openStream());
+             }
+        } catch(IOException ex) {
+            log.error("Unable to load properties", ex);
+            throw new UnavailableException("Unable to load properties:"+ex.getMessage());
+        }
+
+        // Resolve all properties ending with Path against the servlet context, if possibile
+        String key, value;
+        String realPath;
+        for (Iterator i = tiProps.keySet().iterator(); i.hasNext(); ) {
+            key = (String) i.next();
+            if (key.startsWith("ti.") && key.endsWith("Path")) {
+                value = tiProps.getProperty(key);
+                if (value != null && value.length() > 0) {
+                    realPath = servletContext.getRealPath(value);
+                    if (realPath != null) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("Resolved "+value+" as "+realPath+" for key "+key);
+                        }    
+                        tiProps.setProperty(key, realPath);
+                    } else {
+                        log.info("Unable to resolve path "+value+" for key "+key);
+                    }
+                }    
+            }
+        }    
+    }    
+                    
+    protected void initSpring(ServletContext servletContext) throws ServletException {
+        // Parse the configuration file specified by path or resource
+        try {
+            String paths = servletContext.getInitParameter("springConfig");
+            if (paths != null) {
+                springConfig = paths;
+            }
+
+            URL resource = ServletSourceResolver.resolve(springConfig, true, servletContext);
+            log.info("Loading spring configuration from " + resource);
+            beanFactory = new XmlBeanFactory(new UrlResource(resource));
+
+            // create placeholderconfigurer to bring in some property
+            // values from a Properties file
+            PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
+            cfg.setProperties(tiProps);
+            // now actually do the replacement
+            cfg.postProcessBeanFactory((XmlBeanFactory)beanFactory);
+            
+        } catch (Exception e) {
+            String msg = "Exception loading spring configuration";
+            log.error(msg, e);
+            throw new UnavailableException(msg);
+        }
+    }
+}

Modified: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/StrutsTiServlet.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/StrutsTiServlet.java?rev=240168&r1=240167&r2=240168&view=diff
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/StrutsTiServlet.java (original)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/servlet/StrutsTiServlet.java Thu Aug 25 22:46:03 2005
@@ -81,7 +81,11 @@
         initProperties();
         initSpring();
         initServlet();
-
+        Map params = new HashMap();
+        params.put(SERVLET_MAPPINGS_KEY, servletMappings);
+        ServletConfiguration servletConfiguration = ServletConfiguration.init(getServletContext());
+        processor = servletConfiguration.createRequestProcessor(getServletContext(), "actionRequestProcessor", params);
+ 
         Map initParameters = new HashMap();
         initParameters.putAll(tiProps);
         initParameters.put(SERVLET_MAPPINGS_KEY, servletMappings);

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/Bundle.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/Bundle.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/Bundle.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/Bundle.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,93 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.util;
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ * Convenience class for dealing with resource bundles.
+ */
+public class Bundle {
+
+    private static final String BUNDLE_NAME = "org.apache.ti.util.messages";
+
+    /**
+     * No need, it's all static
+     */
+    private Bundle() {
+    }
+
+    /**
+     * Returns the resource bundle named Bundle[].properties in the
+     * package of the specified class.
+     */
+    private static ResourceBundle getBundle() {
+        return ResourceBundle.getBundle(BUNDLE_NAME);
+    }
+
+
+    /**
+     * Returns the string specified by aKey from the errors.properties bundle.
+     */
+    public static String getString(String aKey) {
+        try {
+            return getBundle().getString(aKey);
+        } catch (Exception e) {
+            return getString("System_StringNotFound", new Object[]{aKey});
+        }
+    }
+
+    /**
+     * Returns the string specified by aKey from the errors.properties bundle.
+     *
+     * @param aKey The key for the message pattern in the bundle.
+     * @param arg  The arg to use in the message format.
+     */
+    public static String getString(String aKey, Object arg) {
+        return getString(aKey, new Object[]{arg});
+    }
+
+    /**
+     * Returns the string specified by aKey from the errors.properties bundle.
+     *
+     * @param aKey The key for the message pattern in the bundle.
+     * @param args The args to use in the message format.
+     */
+    public static String getString(String aKey, Object[] args) {
+        String pattern = getBundle().getString(aKey);
+        MessageFormat format = new MessageFormat(pattern);
+
+        return format.format(args).toString();
+    }
+
+    /**
+     *
+     */
+    public static String getErrorString(String aKey, Object[] args) {
+        String pattern = getBundle().getString(aKey);
+        MessageFormat format = new MessageFormat(pattern);
+
+        return format.format(args);
+    }
+
+    public static String getErrorString(String aKey) {
+        return getBundle().getString(aKey);
+    }
+
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/MessageResources.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/MessageResources.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/MessageResources.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/MessageResources.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.util;
+
+import java.util.Locale;
+
+// TODO: temporary stub interface for message resources
+
+public interface MessageResources {
+
+    public String getMessage(Locale locale, String key);
+
+    public String getMessage(Locale locale, String key, Object[] args);
+}

Modified: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/ServletSourceResolver.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/ServletSourceResolver.java?rev=240168&r1=240167&r2=240168&view=diff
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/ServletSourceResolver.java (original)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/ServletSourceResolver.java Thu Aug 25 22:46:03 2005
@@ -17,6 +17,12 @@
  */
 package org.apache.ti.util;
 
+import org.apache.commons.chain.web.WebContext;
+import org.apache.commons.chain.web.servlet.ServletWebContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.servlet.ServletContext;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -24,16 +30,9 @@
 import java.util.Enumeration;
 import java.util.List;
 
-import javax.servlet.ServletContext;
-
-import org.apache.commons.chain.web.WebContext;
-import org.apache.commons.chain.web.servlet.ServletWebContext;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
 
 /**
- *  Source resolver that uses the servlet resource locator
+ * Source resolver that uses the servlet resource locator
  */
 public class ServletSourceResolver implements SourceResolver {
 
@@ -57,9 +56,26 @@
             throws IOException, MalformedURLException {
 
         ServletContext servletContext = ((ServletWebContext) context).getContext();
+        return resolveList(path, false, servletContext);
+    }
+
+    public static URL resolve(String path, boolean force, ServletContext servletContext)
+            throws IOException, MalformedURLException {
+
+        List list = resolveList(path, force, servletContext);
+        if (list.size() > 0) {
+            return (URL) list.get(0);
+        } else {
+            return null;
+        }
+    }
+
+    public static List resolveList(String path, boolean force, ServletContext servletContext)
+            throws IOException, MalformedURLException {
+
         ClassLoader loader = Thread.currentThread().getContextClassLoader();
         if (loader == null) {
-            loader = this.getClass().getClassLoader();
+            loader = ServletSourceResolver.class.getClassLoader();
         }
         ArrayList resolvedUrls = new ArrayList();
 
@@ -77,7 +93,7 @@
                             + "trying classloader.");
                 }
                 Enumeration e = loader.getResources(path);
-                if (!e.hasMoreElements()) {
+                if (force && !e.hasMoreElements()) {
                     String msg = "Resource not found: " + path;
                     log.error(msg);
                     throw new IOException(msg);

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/ConfigInitializationException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/ConfigInitializationException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/ConfigInitializationException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/ConfigInitializationException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,57 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.util.config;
+
+/**
+ * <p/>
+ * Exception thrown when an error occurs loading the NetUI configuration file
+ * into a web application.
+ * </p>
+ */
+public class ConfigInitializationException
+        extends Exception {
+
+    /**
+     * Default constructor.
+     */
+    public ConfigInitializationException() {
+        super();
+    }
+
+    /**
+     * @param message
+     */
+    public ConfigInitializationException(String message) {
+        super(message);
+    }
+
+    /**
+     * @param cause
+     */
+    public ConfigInitializationException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * @param message
+     * @param cause
+     */
+    public ConfigInitializationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/ConfigUtil.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/ConfigUtil.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/ConfigUtil.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/ConfigUtil.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,182 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.util.config;
+
+import org.apache.ti.schema.config.NetuiConfigDocument;
+import org.apache.ti.schema.config.NetuiConfigDocument.NetuiConfig;
+import org.apache.ti.util.internal.InternalStringBuilder;
+import org.apache.ti.util.logging.Logger;
+import org.apache.xmlbeans.XmlError;
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlOptions;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+
+/**
+ * <p/>
+ * Utility class for reading properties from the NetUI configuration file.
+ * <br/>
+ * <br/>
+ * The webapp runtime is read from the URL passed to the {@link #init} method.
+ * The configuration should be initialized with this method and a valid URL
+ * before the first time the {@link #getConfig()} method is called.  If the configuration
+ * has not been initialized, {@link #getConfig()} will initialize a bare bones runtime
+ * configuration.  Depending on the web application, this default configuration
+ * may lead to runtime errors.
+ * <br/>
+ * <br/>
+ * </p>
+ */
+public class ConfigUtil {
+
+    // @todo: need to change NetuiConfigDocument.NetuiConfig to NetUIConfig
+    // @todo: need to provide a read-only implementation so that users can't edit the config file on the fly
+
+    private static final Logger LOGGER = Logger.getInstance(ConfigUtil.class);
+
+    private static final String DEFAULT_CONFIG = "org/apache/ti/util/config/struts-ti-config-default.xml";
+
+    private static NetuiConfigDocument _config = null;
+
+    /* do not construct */
+    protected ConfigUtil() {
+    }
+
+    /**
+     * <p/>
+     * Initialize the NetUI configuration data.
+     * <br/>
+     * <br/>
+     * This method can be called exactly once in a J2EE web application.  The
+     * URL parameter should reference a
+     * netui-config.xml file.  If an error occurs loading the configuration
+     * file, a {@link ConfigInitializationException} will be thrown.
+     * </p>
+     *
+     * @param url the URL from which to read the configuration file
+     * @throws ConfigInitializationException thrown when an error occurs loading the configuration file
+     *                                       or when the configuration is reinitialized.
+     */
+    public static final void init(URL url)
+            throws ConfigInitializationException {
+        if (_config != null)
+            throw new ConfigInitializationException("Config initialization already completed; unable to reload the NetUI config file.");
+
+        internalInit(url);
+    }
+
+    public static final boolean isInit() {
+        return (_config != null);
+    }
+
+    /**
+     * Internal method used to re-initialize the static class member that holds the
+     * ConfigDocument.  Note, this method does <b>no</b> checks to ensure that an
+     * existing document is being overwritten.  The behavior of ConfigUtil clients
+     * is undefined if their initial configuration is re-loaded.
+     *
+     * @param url The URL that contains the config document to load
+     * @throws ConfigInitializationException thrown when an error occurs loading the
+     *                                       configuration file.
+     */
+    protected static final void internalInit(URL url)
+            throws ConfigInitializationException {
+
+        // when initialized with a null URL, revert to using a default, barebones config file
+        if (url == null) {
+            ClassLoader cl = Thread.currentThread().getContextClassLoader();
+            url = cl.getResource(DEFAULT_CONFIG);
+
+            if (url == null)
+                throw new ConfigInitializationException("The NetUI runtime could not find the default config file.  " +
+                        "The webapp may not function properly.");
+
+            if (LOGGER.isInfoEnabled())
+                LOGGER.info("Loading the default NetUI config file.  The runtime will be configured " +
+                        "with a set of minimum parameters.");
+        }
+
+        if (_config == null) {
+            try {
+                XmlOptions loadOptions = new XmlOptions();
+                loadOptions.setLoadLineNumbers();
+                _config = NetuiConfigDocument.Factory.parse(url, loadOptions);
+            }
+                    // XmlException | IOException
+            catch (Exception ex) {
+                assert ex instanceof XmlException || ex instanceof IOException;
+
+                throw new ConfigInitializationException("Unable load the NetUI config file.  Cause: " + ex, ex);
+            }
+        }
+
+        assert _config != null;
+
+        // Validate the document.
+        XmlOptions validateOptions = new XmlOptions();
+        ArrayList errorList = new ArrayList();
+        validateOptions.setErrorListener(errorList);
+        boolean isValid = _config.validate(validateOptions);
+
+        // Throw an exception if the XML is invalid.
+        if (!isValid) {
+            InternalStringBuilder msg = new InternalStringBuilder("Invalid NetUI configuration file.");
+
+            for (int i = 0; i < errorList.size(); i++) {
+                XmlError error = (XmlError) errorList.get(i);
+                msg.append("\n    line ");
+                msg.append(error.getLine());
+                msg.append(": ");
+                msg.append(error.getMessage());
+                msg.append(" (");
+                msg.append(error.getCursorLocation().toString());
+                msg.append(")");
+            }
+
+            throw new ConfigInitializationException(msg.toString());
+        }
+    }
+
+    /**
+     * Get the NetUI configuration object.
+     *
+     * @return a configuration bean that contains data
+     *         parsed from the netui-config.xml file.
+     */
+    public static NetuiConfig getConfig() {
+        if (_config != null) {
+            return _config.getNetuiConfig();
+        }
+        /*
+          If the config file wasn't initialized, attempt to initialize a configuration
+          from the default config file contained in the utility JAR.
+         */
+        else {
+            /*
+              This hopefully never happens and would only occur if the default config file isn't found in the util JAR.
+             */
+            if (LOGGER.isErrorEnabled())
+                LOGGER.error("An error occurred parsing the default config file.  " +
+                        "The NetUI runtime is not properly configured.");
+
+            throw new IllegalStateException("The NetUI runtime could not find the default config file.  The webapp may not function properly.");
+        }
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/struts-ti-config-default.xml
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/struts-ti-config-default.xml?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/struts-ti-config-default.xml (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/config/struts-ti-config-default.xml Thu Aug 25 22:46:03 2005
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<netui-config xmlns="http://struts.apache.org/ti/2004/server/config">
+
+    <expression-languages>
+        <default-language>netuiel</default-language>
+        <expression-language>
+            <name>netuiel</name>
+            <factory-class>org.apache.ti.script.el.ExpressionEvaluatorImpl$NetUIELEngineFactory</factory-class>
+        </expression-language>
+    </expression-languages>
+
+</netui-config>

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/internal/BouncyClassLoader.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/internal/BouncyClassLoader.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/internal/BouncyClassLoader.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/internal/BouncyClassLoader.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,104 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.util.internal;
+
+import org.apache.ti.util.internal.concurrent.InternalConcurrentHashMap;
+import org.apache.ti.util.logging.Logger;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.SecureClassLoader;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * ClassLoader that takes precendence over its parent for loading classes, and which is aware of timestamps on its
+ * binaries (and thus knows when it needs to be bounced.
+ */
+public class BouncyClassLoader
+        extends SecureClassLoader {
+
+    private static final Logger _log = Logger.getInstance(BouncyClassLoader.class);
+
+    private InternalConcurrentHashMap/*< File, Long >*/ _timestamps = new InternalConcurrentHashMap/*< File, Long >*/();
+    private File[] _classDirs;
+
+
+    public BouncyClassLoader(File[] classDirs, ClassLoader parent) {
+        super(parent);
+        _classDirs = classDirs;
+    }
+
+    public Class loadClass(String name) throws ClassNotFoundException {
+        Class ret = findLoadedClass(name);
+        if (ret != null) return ret;
+
+        String baseName = File.separatorChar + name.replace('.', File.separatorChar).concat(".class");
+
+        for (int i = 0; i < _classDirs.length; ++i) {
+            File file = new File(_classDirs[i].getPath() + baseName);
+
+            if (file.exists()) {
+                _timestamps.put(file, new Long(file.lastModified()));
+                byte[] bytes = getBytes(file);
+                if (bytes != null) return super.defineClass(name, bytes, 0, bytes.length);
+            }
+        }
+
+        return super.loadClass(name);
+    }
+
+    byte[] getBytes(File file) {
+        try {
+            BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
+
+            try {
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                int c;
+
+                while ((c = in.read()) != -1) {
+                    out.write(c);
+                }
+
+                return out.toByteArray();
+            } finally {
+                in.close();
+            }
+        } catch (FileNotFoundException e) {
+            _log.error("Could not read class file " + file, e);
+        } catch (IOException e) {
+            _log.error("Error while reading class file " + file, e);
+        }
+
+        return null;
+    }
+
+    public boolean isStale() {
+        for (Iterator i = _timestamps.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            if (((File) entry.getKey()).lastModified() > ((Long) entry.getValue()).longValue()) return true;
+        }
+
+        return false;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/internal/DiscoveryUtils.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/internal/DiscoveryUtils.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/internal/DiscoveryUtils.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/util/internal/DiscoveryUtils.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,169 @@
+/*
+ * Copyright 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.
+ *
+ * $Header:$
+ */
+package org.apache.ti.util.internal;
+
+import org.apache.ti.util.logging.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+
+/**
+ * Utility methods for discovering implementor classes on the classpath.  An implementor class is declared in the
+ * standard way, in a file within META-INF/services where the file name is the class name of the desired interface, and
+ * the file contains the class name of the implementation.  For example, to declare test.MyServiceImpl as a
+ * test.MyService implementation, the file META-INF/services/test.MyService is put on classpath (e.g., in a JAR),
+ * with contents "test.MyServiceImpl".
+ */
+public class DiscoveryUtils {
+
+    private static final Logger _log = Logger.getInstance(DiscoveryUtils.class);
+
+
+    /**
+     * Get the ClassLoader from which implementor classes will be discovered and loaded.
+     */
+    public static ClassLoader getClassLoader() {
+        try {
+            ClassLoader cl = Thread.currentThread().getContextClassLoader();
+            if (cl != null) return cl;
+        } catch (SecurityException e) {
+            if (_log.isDebugEnabled()) {
+                _log.debug("Could not get thread context classloader.", e);
+            }
+        }
+
+        if (_log.isTraceEnabled()) {
+            _log.trace("Can't use thread context classloader; using classloader for " + DiscoveryUtils.class.getName());
+        }
+
+        return DiscoveryUtils.class.getClassLoader();
+    }
+
+    /**
+     * Get all implementor classes (on the context classpath) that implement a given interface.
+     *
+     * @param interfaceType the Class that represents the interface.
+     * @return an array of Classes that are implementations of <code>interfaceType</code>.
+     */
+    public static Class[] getImplementorClasses(Class interfaceType) {
+        String interfaceName = interfaceType.getName();
+        ArrayList/*< Class >*/ classes = new ArrayList/*< Class >*/();
+        ClassLoader classLoader = getClassLoader();
+
+        try {
+            Enumeration e = classLoader.getResources("META-INF/services/" + interfaceName);
+
+            while (e.hasMoreElements()) {
+                URL url = (URL) e.nextElement();
+
+                if (_log.isTraceEnabled()) {
+                    _log.trace("Found implementor entry for interface " + interfaceName + " at " + url);
+                }
+
+                InputStream is = null;
+                String className = null;
+
+                try {
+                    is = url.openStream();
+                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+                    className = reader.readLine().trim();
+                    Class implementorClass = loadImplementorClass(className, interfaceType, classLoader);
+                    if (implementorClass != null) classes.add(implementorClass);
+                } catch (IOException ioe) {
+                    _log.error("Could not read implementor class entry at + " + url);
+                } finally {
+                    if (is != null) is.close();
+                }
+            }
+        } catch (IOException e) {
+            _log.error("Could not discover implementors for " + interfaceName, e);
+        }
+
+        return (Class[]) classes.toArray(new Class[0]);
+    }
+
+    public static Object newImplementorInstance(String className, Class interfaceType) {
+        Class implementorClass = loadImplementorClass(className, interfaceType);
+
+        if (implementorClass != null) {
+            try {
+                return implementorClass.newInstance();
+            } catch (IllegalAccessException e) {
+                _log.error("Could not instantiate " + className + " for interface " + interfaceType.getName(), e);
+            } catch (InstantiationException e) {
+                _log.error("Could not instantiate " + className + " for interface " + interfaceType.getName(), e);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Load an implementor class from the context classloader.
+     *
+     * @param className     the name of the implementor class.
+     * @param interfaceType the interface that the given class should implement.
+     * @return the implementor Class, or <code>null</code> if an error occurred (the error will be logged).
+     */
+    public static Class loadImplementorClass(String className, Class interfaceType) {
+        return loadImplementorClass(className, interfaceType, getClassLoader());
+    }
+
+    /**
+     * Load an implementor class from the context classloader.
+     *
+     * @param className     the name of the implementor class.
+     * @param interfaceType the interface that the given class should implement.
+     * @param classLoader   the ClassLoader from which to load the implementor class.
+     * @return the implementor Class, or <code>null</code> if an error occurred (the error will be logged).
+     */
+    private static Class loadImplementorClass(String className, Class interfaceType, ClassLoader classLoader) {
+        try {
+            if (_log.isDebugEnabled()) {
+                _log.debug("Trying to load implementor class for interface " + interfaceType.getName()
+                        + ": " + className);
+            }
+
+            Class implementorClass = classLoader.loadClass(className);
+
+            if (interfaceType.isAssignableFrom(implementorClass)) {
+                return implementorClass;
+            } else {
+                _log.error("Implementor class " + className + " does not implement interface "
+                        + interfaceType.getName());
+            }
+        } catch (ClassNotFoundException cnfe) {
+            //
+            // This will happen when the user class was built against an out-of-date interface.
+            //
+            _log.error("Could not find implementor class " + className + " for interface " + interfaceType.getName(),
+                    cnfe);
+        } catch (LinkageError le) {
+            _log.error("Linkage error when loading implementor class " + className + " for interface "
+                    + interfaceType.getName(), le);
+        }
+
+        return null;
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org