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