0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: */
0027:
0028: package com.caucho.config;
0029:
0030: import com.caucho.config.program.NodeBuilderChildProgram;
0031: import com.caucho.config.program.ConfigProgram;
0032: import com.caucho.config.types.Validator;
0033: import com.caucho.config.type.*;
0034: import com.caucho.config.attribute.*;
0035: import com.caucho.el.ELParser;
0036: import com.caucho.el.Expr;
0037: import com.caucho.loader.*;
0038: import com.caucho.util.*;
0039: import com.caucho.vfs.*;
0040: import com.caucho.webbeans.component.ComponentImpl;
0041: import com.caucho.webbeans.context.DependentScope;
0042: import com.caucho.webbeans.context.ScopeContext;
0043: import com.caucho.xml.*;
0044:
0045: import org.w3c.dom.*;
0046:
0047: import javax.el.*;
0048: import java.io.Closeable;
0049: import java.io.IOException;
0050: import java.util.*;
0051: import java.util.logging.Level;
0052: import java.util.logging.Logger;
0053:
0054: /**
0055: * The ConfigContext contains the state of the current configuration.
0056: */
0057: public class ConfigContext {
0058: private final static L10N L = new L10N(ConfigContext.class);
0059: private final static Logger log = Logger
0060: .getLogger(ConfigContext.class.getName());
0061:
0062: private final static QName RESIN_TYPE = new QName("resin:type",
0063: null);
0064: private final static QName RESIN_TYPE_NS = new QName("resin:type",
0065: "http://caucho.com/ns/resin/core");
0066:
0067: private final static QName RESIN_CLASS = new QName("resin:class",
0068: null);
0069: private final static QName RESIN_CLASS_NS = new QName(
0070: "resin:class", "http://caucho.com/ns/resin/core");
0071:
0072: private final static QName TEXT = new QName("#text");
0073: private final static QName VALUE = new QName("value");
0074:
0075: private final static Object NULL = new Object();
0076:
0077: private final static HashSet<QName> _resinClassSet = new HashSet<QName>();
0078:
0079: private static ThreadLocal<ConfigContext> _currentBuilder = new ThreadLocal<ConfigContext>();
0080:
0081: private Config _config;
0082:
0083: private ArrayList<ValidatorEntry> _validators = new ArrayList<ValidatorEntry>();
0084:
0085: private ConfigELContext _elContext = new ConfigELContext();
0086:
0087: private DependentScope _dependentScope;
0088:
0089: private ArrayList<Dependency> _dependList;
0090: private Document _dependDocument;
0091:
0092: private String _baseUri;
0093:
0094: public ConfigContext() {
0095: }
0096:
0097: public ConfigContext(ComponentImpl component, Object value,
0098: ScopeContext scope) {
0099: this ();
0100:
0101: _dependentScope = new DependentScope(component, value, scope);
0102: }
0103:
0104: public ConfigContext(ScopeContext scope) {
0105: this ();
0106:
0107: _dependentScope = new DependentScope(scope);
0108: }
0109:
0110: ConfigContext(Config config) {
0111: _config = config;
0112: }
0113:
0114: public static ConfigContext create() {
0115: ConfigContext env = _currentBuilder.get();
0116:
0117: if (env != null)
0118: return env;
0119: else
0120: return new ConfigContext();
0121: }
0122:
0123: public static ConfigContext createForProgram() {
0124: return new ConfigContext();
0125: }
0126:
0127: public static ConfigContext getCurrentBuilder() {
0128: return _currentBuilder.get();
0129: }
0130:
0131: public static ConfigContext getCurrent() {
0132: return _currentBuilder.get();
0133: }
0134:
0135: // s/b private?
0136: static void setCurrentBuilder(ConfigContext builder) {
0137: _currentBuilder.set(builder);
0138: }
0139:
0140: /**
0141: * Returns the file var
0142: */
0143: public String getBaseUri() {
0144: return _baseUri;
0145: }
0146:
0147: /**
0148: * WebBeans method
0149: *
0150: * @param aThis
0151: * @param value
0152: */
0153: public void addDestructor(ComponentImpl comp, Object value) {
0154: if (_dependentScope != null)
0155: _dependentScope.addDestructor(comp, value);
0156: else if (comp instanceof Closeable)
0157: Environment.addCloseListener((Closeable) comp);
0158: }
0159:
0160: public boolean canInject(ScopeContext scope) {
0161: return _dependentScope == null
0162: || _dependentScope.canInject(scope);
0163: }
0164:
0165: /**
0166: * Returns the component value for the dependent scope
0167: *
0168: * @param aThis
0169: * @return
0170: */
0171: public Object get(ComponentImpl comp) {
0172: if (_dependentScope != null)
0173: return _dependentScope.get(comp);
0174: else
0175: return null;
0176: }
0177:
0178: public Config getConfig() {
0179: return _config;
0180: }
0181:
0182: /**
0183: * WebBeans dependent scope setting
0184: *
0185: * @param aThis
0186: * @param obj
0187: */
0188: public void put(ComponentImpl comp, Object obj) {
0189: if (_dependentScope == null)
0190: _dependentScope = new DependentScope();
0191:
0192: _dependentScope.put(comp, obj);
0193: }
0194:
0195: /**
0196: * Returns true if EL expressions are used.
0197: */
0198: private boolean isEL() {
0199: // server/26b6
0200: return _config == null || _config.isEL();
0201: }
0202:
0203: public boolean isIgnoreEnvironment() {
0204: return _config != null && _config.isIgnoreEnvironment();
0205: }
0206:
0207: /**
0208: * External call to configure a bean based on a top-level node.
0209: * The init() and replaceObject() are not called.
0210: *
0211: * @param bean the object to be configured.
0212: */
0213: public Object configure(Object bean, Node top)
0214: throws LineConfigException {
0215: if (bean == null)
0216: throw new NullPointerException();
0217:
0218: ConfigContext oldBuilder = _currentBuilder.get();
0219: try {
0220: _currentBuilder.set(this );
0221:
0222: ConfigType type = TypeFactory.getType(bean.getClass());
0223:
0224: configureBean(bean, top);
0225:
0226: type.init(bean);
0227:
0228: return type.replaceObject(bean);
0229: } catch (LineConfigException e) {
0230: throw e;
0231: } catch (Exception e) {
0232: throw error(e, top);
0233: } finally {
0234: _currentBuilder.set(oldBuilder);
0235: }
0236: }
0237:
0238: /**
0239: * External call to configure a bean based on a top-level node, calling
0240: * init() and replaceObject() when done.
0241: *
0242: * @param bean the bean to be configured
0243: * @param top the top-level XML configuration node
0244: * @return the configured object, or the factory generated object
0245: */
0246: public void configureBean(Object bean, Node top)
0247: throws LineConfigException {
0248: ConfigContext oldBuilder = _currentBuilder.get();
0249: String oldFile = _baseUri;
0250: ArrayList<Dependency> oldDependList = _dependList;
0251:
0252: try {
0253: _currentBuilder.set(this );
0254:
0255: if (top instanceof QNode) {
0256: QNode qNode = (QNode) top;
0257:
0258: _baseUri = qNode.getBaseURI();
0259: }
0260:
0261: _dependList = getDependencyList(top);
0262:
0263: ConfigType type = TypeFactory.getType(bean.getClass());
0264:
0265: configureNode(top, bean, type);
0266: } finally {
0267: _currentBuilder.set(oldBuilder);
0268:
0269: _dependList = oldDependList;
0270: _baseUri = oldFile;
0271: }
0272: }
0273:
0274: /**
0275: * External call to configure a bean's attribute.
0276: *
0277: * @param bean the bean to be configured
0278: * @param attribute the node representing the configured attribute
0279: * @throws LineConfigException
0280: */
0281: public void configureAttribute(Object bean, Node attribute)
0282: throws LineConfigException {
0283: String attrName = attribute.getNodeName();
0284:
0285: if (attrName.equals("resin:type"))
0286: return;
0287: else if (attrName.startsWith("xmlns"))
0288: return;
0289:
0290: Thread thread = Thread.currentThread();
0291: ClassLoader oldLoader = thread.getContextClassLoader();
0292: ConfigContext oldBuilder = getCurrentBuilder();
0293: try {
0294: setCurrentBuilder(this );
0295:
0296: ConfigType type = TypeFactory.getType(bean.getClass());
0297:
0298: QName qName = ((QAbstractNode) attribute).getQName();
0299:
0300: type.beforeConfigure(this , bean, attribute);
0301:
0302: configureChildNode(attribute, qName, bean, type);
0303:
0304: type.afterConfigure(this , bean);
0305: } catch (LineConfigException e) {
0306: throw e;
0307: } catch (Exception e) {
0308: throw error(e, attribute);
0309: } finally {
0310: setCurrentBuilder(oldBuilder);
0311: thread.setContextClassLoader(oldLoader);
0312: }
0313: }
0314:
0315: /**
0316: * Configures a bean, calling its init() and replaceObject() methods.
0317: *
0318: * @param typeStrategy the strategy for handling the bean's type
0319: * @param bean the bean instance
0320: * @param top the configuration top
0321: * @return the configured bean, possibly the replaced object
0322: * @throws LineConfigException
0323: */
0324: private Object configureNode(Node node, Object bean, ConfigType type)
0325: throws LineConfigException {
0326: Thread thread = Thread.currentThread();
0327: ClassLoader oldLoader = thread.getContextClassLoader();
0328:
0329: try {
0330: type.beforeConfigure(this , bean, node);
0331: type.beforeConfigureBean(this , bean, node);
0332:
0333: configureNodeAttributes(node, bean, type);
0334:
0335: for (Node childNode = node.getFirstChild(); childNode != null; childNode = childNode
0336: .getNextSibling()) {
0337: QName qName = ((QAbstractNode) childNode).getQName();
0338:
0339: configureChildNode(childNode, qName, bean, type);
0340: }
0341:
0342: type.afterConfigure(this , bean);
0343: } catch (LineConfigException e) {
0344: throw e;
0345: } catch (Exception e) {
0346: throw error(e, node);
0347: } finally {
0348: thread.setContextClassLoader(oldLoader);
0349: }
0350:
0351: return bean;
0352: }
0353:
0354: /**
0355: * Configures a bean, calling its init() and replaceObject() methods.
0356: *
0357: * @param typeStrategy the strategy for handling the bean's type
0358: * @param bean the bean instance
0359: * @param top the configuration top
0360: * @return the configured bean, possibly the replaced object
0361: * @throws LineConfigException
0362: */
0363: private void configureNodeAttributes(Node node, Object bean,
0364: ConfigType type) throws Exception {
0365: if (node instanceof QAttributedNode) {
0366: Node child = ((QAttributedNode) node).getFirstAttribute();
0367:
0368: for (; child != null; child = child.getNextSibling()) {
0369: Attr attr = (Attr) child;
0370: QName qName = ((QNode) attr).getQName();
0371:
0372: configureChildNode(attr, qName, bean, type);
0373: }
0374: } else {
0375: NamedNodeMap attrList = node.getAttributes();
0376: if (attrList != null) {
0377: int length = attrList.getLength();
0378: for (int i = 0; i < length; i++) {
0379: Attr attr = (Attr) attrList.item(i);
0380: QName qName = ((QNode) attr).getQName();
0381:
0382: configureChildNode(attr, qName, bean, type);
0383: }
0384: }
0385: }
0386: }
0387:
0388: private void configureChildNode(Node childNode, QName qName,
0389: Object bean, ConfigType type) throws Exception {
0390: if (childNode instanceof Attr
0391: && (qName.getName().startsWith("xmlns") || _resinClassSet
0392: .contains(qName))) {
0393: return;
0394: }
0395:
0396: Attribute attrStrategy;
0397:
0398: try {
0399: attrStrategy = type.getAttribute(qName);
0400:
0401: if (attrStrategy == null)
0402: attrStrategy = type.getProgramAttribute();
0403:
0404: if (attrStrategy == null)
0405: attrStrategy = TypeFactory.getFactory()
0406: .getEnvironmentAttribute(qName);
0407:
0408: if (attrStrategy == null) {
0409: if (childNode instanceof Element
0410: || childNode instanceof Attr) {
0411: throw error(L.l(
0412: "'{0}' is an unknown property of '{1}'.",
0413: qName.getName(), type.getTypeName()),
0414: childNode);
0415: }
0416:
0417: return;
0418: }
0419:
0420: if (attrStrategy.isProgram()) {
0421: attrStrategy.setValue(bean, qName, buildProgram(
0422: attrStrategy, childNode));
0423: return;
0424: } else if (attrStrategy.isNode()) {
0425: attrStrategy.setValue(bean, qName, childNode);
0426: return;
0427: }
0428:
0429: ConfigType childType = null;
0430:
0431: if (childNode instanceof Element)
0432: childType = createResinType(attrStrategy,
0433: (Element) childNode);
0434:
0435: Object childBean;
0436: String text;
0437:
0438: if (childType != null)
0439: childBean = childType.create(bean);
0440: else if (attrStrategy.isAllowText()
0441: && (text = getTextValue(childNode)) != null) {
0442: boolean isTrim = isTrim(childNode);
0443:
0444: if (isEL()
0445: && attrStrategy.isEL()
0446: && (text.indexOf("#{") >= 0 || text
0447: .indexOf("${") >= 0)) {
0448: if (isTrim)
0449: text = text.trim();
0450:
0451: Object elValue = eval(attrStrategy, text);
0452:
0453: // ioc/2410
0454: if (elValue != NULL)
0455: attrStrategy.setValue(bean, qName, elValue);
0456: else
0457: attrStrategy.setValue(bean, qName, null);
0458: } else {
0459: setText(bean, qName, text, attrStrategy, isTrim);
0460: }
0461:
0462: return;
0463: } else
0464: childBean = attrStrategy.create(bean);
0465:
0466: if (childBean != null) {
0467: ConfigType childBeanType = TypeFactory
0468: .getType(childBean.getClass());
0469:
0470: if (childNode instanceof Element)
0471: configureNode(childNode, childBean, childBeanType);
0472: else
0473: configureChildNode(childNode, TEXT, childBean,
0474: childBeanType);
0475:
0476: childBeanType.init(childBean);
0477:
0478: Object newBean = attrStrategy.replaceObject(childBean);
0479: if (newBean != childBean)
0480: childBean = newBean;
0481: else
0482: childBean = childBeanType.replaceObject(childBean);
0483:
0484: attrStrategy.setValue(bean, qName, childBean);
0485: } else if ((childBean = getElementValue(attrStrategy,
0486: childNode)) != null) {
0487: if (childBean != NULL)
0488: attrStrategy.setValue(bean, qName, childBean);
0489: else
0490: attrStrategy.setValue(bean, qName, null);
0491: } else {
0492: ConfigType attrType = attrStrategy.getConfigType();
0493:
0494: String textValue;
0495:
0496: if (attrType.isNoTrim())
0497: textValue = textValueNoTrim(childNode);
0498: else
0499: textValue = textValue(childNode);
0500:
0501: if (isEL() && attrType.isEL()
0502: && textValue.indexOf("${") >= 0) {
0503: childType = attrStrategy.getConfigType();
0504:
0505: Object value = childType
0506: .valueOf(evalObject(textValue));
0507:
0508: attrStrategy.setValue(bean, qName, value);
0509: } else
0510: attrStrategy.setText(bean, qName, textValue);
0511: }
0512: } catch (LineConfigException e) {
0513: throw e;
0514: } catch (Exception e) {
0515: throw error(e, childNode);
0516: }
0517: }
0518:
0519: private void setText(Object bean, QName qName, String text,
0520: Attribute attrStrategy, boolean isTrim) throws Exception {
0521: ConfigType attrType = attrStrategy.getConfigType();
0522:
0523: if (isTrim && !attrType.isNoTrim())
0524: text = text.trim();
0525:
0526: if (isEL() && attrType.isEL() && text.indexOf("${") >= 0) {
0527: ConfigType childType = attrStrategy.getConfigType();
0528:
0529: Object value = childType.valueOf(evalObject(text));
0530:
0531: attrStrategy.setValue(bean, qName, value);
0532: } else
0533: attrStrategy.setText(bean, qName, text);
0534: }
0535:
0536: private boolean isTrim(Node node) {
0537: if (node instanceof Attr)
0538: return false;
0539: else if (node instanceof Element) {
0540: Element elt = (Element) node;
0541:
0542: if (!"".equals(elt.getAttribute("xml:space")))
0543: return false;
0544: }
0545:
0546: return true;
0547: }
0548:
0549: private ConfigProgram buildProgram(Attribute attr, Node node) {
0550: return new NodeBuilderChildProgram(node);
0551: }
0552:
0553: private void configureChildAttribute(Attr childNode, QName qName,
0554: Object bean, ConfigType type) throws Exception {
0555: if (qName.getName().startsWith("xmlns")
0556: || _resinClassSet.contains(qName)) {
0557: return;
0558: }
0559:
0560: Attribute attrStrategy;
0561:
0562: try {
0563: attrStrategy = type.getAttribute(qName);
0564:
0565: if (attrStrategy == null) {
0566: throw error(L.l(
0567: "'{0}' is an unknown property of '{1}'.", qName
0568: .getName(), type.getTypeName()),
0569: childNode);
0570: }
0571:
0572: if (attrStrategy.isProgram()) {
0573: attrStrategy.setValue(bean, qName, buildProgram(
0574: attrStrategy, childNode));
0575: return;
0576: } else if (attrStrategy.isNode()) {
0577: attrStrategy.setValue(bean, qName, childNode);
0578: return;
0579: }
0580:
0581: String textValue = childNode.getValue();
0582:
0583: attrStrategy.setText(bean, qName, textValue);
0584: } catch (LineConfigException e) {
0585: throw e;
0586: } catch (Exception e) {
0587: throw error(e, childNode);
0588: }
0589: }
0590:
0591: Object configureValue(Node node) {
0592: String value = textValue(node);
0593:
0594: if (isEL() && value != null && value.startsWith("${")
0595: && value.endsWith("}")) {
0596: return evalObject(value);
0597: } else
0598: return value;
0599: }
0600:
0601: public void setDependentScope(DependentScope scope) {
0602: _dependentScope = scope;
0603: }
0604:
0605: public DependentScope getDependentScope() {
0606: if (_dependentScope == null)
0607: _dependentScope = new DependentScope();
0608:
0609: return _dependentScope;
0610: }
0611:
0612: public ArrayList<Dependency> getDependencyList() {
0613: return _dependList;
0614: }
0615:
0616: ArrayList<Dependency> getDependencyList(Node node) {
0617: ArrayList<Dependency> dependList = null;
0618:
0619: if (node instanceof QElement) {
0620: QElement qelt = (QElement) node;
0621:
0622: /* XXX: line #
0623: builder.setLocation(bean, qelt.getBaseURI(),
0624: qelt.getFilename(), qelt.getLine());
0625: builder.setNode(bean, qelt);
0626: */
0627:
0628: QDocument doc = (QDocument) qelt.getOwnerDocument();
0629:
0630: if (doc == null)
0631: return null;
0632: else if (doc == _dependDocument)
0633: return _dependList;
0634:
0635: _dependDocument = doc;
0636:
0637: ArrayList<Path> pathList;
0638: pathList = doc.getDependList();
0639:
0640: if (pathList != null) {
0641: dependList = new ArrayList<Dependency>();
0642:
0643: for (int i = 0; i < pathList.size(); i++) {
0644: dependList.add(new Depend(pathList.get(i)));
0645: }
0646: }
0647:
0648: _dependList = dependList;
0649: }
0650:
0651: return dependList;
0652: }
0653:
0654: /**
0655: * Create a custom resin:type value.
0656: */
0657: ConfigType createResinType(Attribute attrStrategy, Element node)
0658: throws Exception {
0659: ConfigType childType = attrStrategy.getConfigType();
0660:
0661: String type = null;
0662:
0663: if (node instanceof QAttributedNode) {
0664: Node child = ((QAttributedNode) node).getFirstAttribute();
0665:
0666: for (; child != null; child = child.getNextSibling()) {
0667: Attr attr = (Attr) child;
0668: QName qName = ((QNode) attr).getQName();
0669:
0670: if (_resinClassSet.contains(qName)) {
0671: type = attr.getValue();
0672: break;
0673: }
0674: }
0675: } else {
0676: NamedNodeMap attrList = node.getAttributes();
0677: if (attrList != null) {
0678: int length = attrList.getLength();
0679: for (int i = 0; i < length; i++) {
0680: Attr attr = (Attr) attrList.item(i);
0681: QName qName = ((QNode) attr).getQName();
0682:
0683: if (_resinClassSet.contains(qName)) {
0684: type = attr.getValue();
0685: break;
0686: }
0687: }
0688: }
0689: }
0690:
0691: if (type != null) {
0692: try {
0693: ClassLoader loader = Thread.currentThread()
0694: .getContextClassLoader();
0695:
0696: Class cl = Class.forName(type, false, loader);
0697:
0698: return TypeFactory.getType(cl);
0699: } catch (Exception e) {
0700: throw ConfigException.create(e);
0701: }
0702: }
0703:
0704: return null;
0705: }
0706:
0707: /**
0708: * Configures a new object given the object's type.
0709: *
0710: * @param type the expected type of the object
0711: * @param node the configuration node
0712: * @return the configured object
0713: * @throws Exception
0714: */
0715: Object configureCreate(Class type, Node node) throws Exception {
0716: Object value = type.newInstance();
0717:
0718: return configure(value, node);
0719: }
0720:
0721: /**
0722: * Returns the variable resolver.
0723: */
0724: public ConfigELContext getELContext() {
0725: return _elContext;
0726: }
0727:
0728: void addValidator(Validator validator) {
0729: if (_validators == null)
0730: _validators = new ArrayList<ValidatorEntry>();
0731:
0732: _validators.add(new ValidatorEntry(validator));
0733: }
0734:
0735: static boolean hasChildren(Node node) {
0736: Node ptr;
0737:
0738: if (node instanceof QAttributedNode) {
0739: Node attr = ((QAttributedNode) node).getFirstAttribute();
0740:
0741: for (; attr != null; attr = attr.getNextSibling()) {
0742: if (!attr.getNodeName().startsWith("xml"))
0743: return true;
0744: }
0745: } else if (node instanceof Element) {
0746: NamedNodeMap attrList = node.getAttributes();
0747: if (attrList != null) {
0748: for (int i = 0; i < attrList.getLength(); i++) {
0749: if (!attrList.item(i).getNodeName().startsWith(
0750: "xml"))
0751: return true;
0752: }
0753: }
0754: }
0755:
0756: for (ptr = node.getFirstChild(); ptr != null; ptr = ptr
0757: .getNextSibling()) {
0758: if (ptr instanceof Element)
0759: return true;
0760: }
0761:
0762: return false;
0763: }
0764:
0765: static String getValue(QName name, Node node, String defaultValue) {
0766: /*
0767: NamedNodeMap attrList = node.getAttributes();
0768: if (attrList != null) {
0769: for (int i = 0; i < attrList.getLength(); i++) {
0770: if (attrList.item(i).getNodeName().equals(name.getName()))
0771: return attrList.item(i).getNodeValue();
0772: }
0773: }
0774: */
0775:
0776: if (node instanceof Element) {
0777: String value = ((Element) node)
0778: .getAttribute(name.getName());
0779:
0780: if (!"".equals(value))
0781: return value;
0782: }
0783:
0784: Node ptr;
0785:
0786: for (ptr = node.getFirstChild(); ptr != null; ptr = ptr
0787: .getNextSibling()) {
0788: QName qName = ((QAbstractNode) ptr).getQName();
0789:
0790: if (name.equals(qName))
0791: return textValue(ptr);
0792: }
0793:
0794: return defaultValue;
0795: }
0796:
0797: /**
0798: * Returns the text value of the node.
0799: */
0800: Object getELValue(Attribute attr, Node node) {
0801: if (node instanceof Attr) {
0802: Attr attrNode = (Attr) node;
0803: String data = attrNode.getNodeValue();
0804:
0805: // server/12h6
0806: if (data != null
0807: && isEL()
0808: && attr.isEL()
0809: && (data.indexOf("#{") >= 0 || data.indexOf("${") >= 0)) {
0810: return eval(attr, data);
0811: }
0812:
0813: return null;
0814: }
0815:
0816: if (!(node instanceof Element))
0817: return null;
0818:
0819: Element elt = (Element) node;
0820: Element childElt = null;
0821:
0822: for (Node child = elt.getFirstChild(); child != null; child = child
0823: .getNextSibling()) {
0824: if (child instanceof Element) {
0825: if (childElt != null)
0826: return null;
0827:
0828: childElt = (Element) child;
0829: }
0830:
0831: else if (child instanceof CharacterData
0832: && !XmlUtil.isWhitespace(((CharacterData) child)
0833: .getData())) {
0834: String data = ((CharacterData) child).getData();
0835:
0836: if (isEL()
0837: && attr.isEL()
0838: && childElt == null
0839: && child.getNextSibling() == null
0840: && (data.indexOf("#{") >= 0 || data
0841: .indexOf("${") >= 0)) {
0842:
0843: String exprString = data.trim();
0844:
0845: ELContext elContext = getELContext();
0846:
0847: ELParser parser = new ELParser(elContext,
0848: exprString);
0849:
0850: Expr expr = parser.parse();
0851:
0852: Object value = expr.getValue(elContext);
0853:
0854: // ioc/2403
0855: return attr.getConfigType().valueOf(value);
0856: }
0857:
0858: return null;
0859: }
0860: }
0861:
0862: return null;
0863: }
0864:
0865: /**
0866: * Returns the text value of the node.
0867: */
0868: String getTextValue(Node node) {
0869: if (node instanceof Attr) {
0870: Attr attrNode = (Attr) node;
0871: String data = attrNode.getNodeValue();
0872:
0873: return data;
0874: }
0875:
0876: if (!(node instanceof Element))
0877: return null;
0878:
0879: Element elt = (Element) node;
0880:
0881: for (Node child = elt.getFirstChild(); child != null; child = child
0882: .getNextSibling()) {
0883: if (child instanceof Element) {
0884: return null;
0885: }
0886:
0887: else if (child instanceof CharacterData) {
0888: String data = ((CharacterData) child).getData();
0889:
0890: if (child.getNextSibling() == null
0891: && !XmlUtil.isWhitespace(data)) {
0892: return data;
0893: } else
0894: return null;
0895: }
0896: }
0897:
0898: return null;
0899: }
0900:
0901: private Object eval(Attribute attr, String data) {
0902: ELContext elContext = getELContext();
0903:
0904: ELParser parser = new ELParser(elContext, data);
0905:
0906: Expr expr = parser.parse();
0907:
0908: Object value = attr.getConfigType().valueOf(elContext, expr);
0909:
0910: if (value != null)
0911: return value;
0912: else
0913: return NULL;
0914: }
0915:
0916: /**
0917: * Returns the text value of the node.
0918: */
0919: Object getElementValue(Attribute attr, Node node) {
0920: if (!(node instanceof Element))
0921: return null;
0922:
0923: Element elt = (Element) node;
0924: Element childElt = null;
0925:
0926: for (Node child = elt.getFirstChild(); child != null; child = child
0927: .getNextSibling()) {
0928: if (child instanceof Element) {
0929: if (childElt != null)
0930: return null;
0931:
0932: childElt = (Element) child;
0933: }
0934:
0935: else if (child instanceof CharacterData
0936: && !XmlUtil.isWhitespace(((CharacterData) child)
0937: .getData())) {
0938: String data = ((CharacterData) child).getData();
0939:
0940: if (isEL()
0941: && attr.isEL()
0942: && childElt == null
0943: && child.getNextSibling() == null
0944: && (data.indexOf("#{") >= 0 || data
0945: .indexOf("${") >= 0)) {
0946: ELContext elContext = getELContext();
0947:
0948: ELParser parser = new ELParser(elContext, data
0949: .trim());
0950:
0951: Expr expr = parser.parse();
0952:
0953: Object value = attr.getConfigType().valueOf(
0954: elContext, expr);
0955:
0956: if (value != null)
0957: return value;
0958: else
0959: return NULL;
0960: }
0961:
0962: return null;
0963: }
0964: }
0965:
0966: if (childElt == null)
0967: return null;
0968:
0969: TypeFactory factory = TypeFactory.getFactory();
0970:
0971: ConfigType childType = factory
0972: .getEnvironmentType(((QElement) childElt).getQName());
0973:
0974: if (childType != null) {
0975: Object childBean = childType.create(null);
0976:
0977: configureNode(childElt, childBean, childType);
0978:
0979: childType.init(childBean);
0980:
0981: Object value = childType.replaceObject(childBean);
0982:
0983: if (value != null)
0984: return value;
0985: else
0986: return NULL;
0987: }
0988:
0989: return null;
0990: }
0991:
0992: /**
0993: * Returns the text value of the node.
0994: */
0995: static String textValue(Node node) {
0996: if (node instanceof Attr)
0997: return node.getNodeValue();
0998: else {
0999: String value = XmlUtil.textValue(node);
1000:
1001: if (value == null || value.equals(""))
1002: return "";
1003: else if (node instanceof Element) {
1004: String space = ((Element) node)
1005: .getAttribute("xml:space");
1006:
1007: if (!space.equals(""))
1008: return value;
1009: }
1010:
1011: return value.trim();
1012: }
1013: }
1014:
1015: /**
1016: * Returns the text value of the node.
1017: */
1018: static String textValueNoTrim(Node node) {
1019: if (node instanceof Attr)
1020: return node.getNodeValue();
1021: else {
1022: String value = XmlUtil.textValue(node);
1023:
1024: if (value == null)
1025: return "";
1026:
1027: return value;
1028: }
1029: }
1030:
1031: /**
1032: * Evaluate as an object
1033: */
1034: public Object evalObject(String exprString) throws ELException {
1035: if (exprString.indexOf("${") >= 0 && isEL()) {
1036: ELParser parser = new ELParser(getELContext(), exprString);
1037: parser.setCheckEscape(true);
1038: Expr expr = parser.parse();
1039:
1040: return expr.getValue(getELContext());
1041: } else
1042: return exprString;
1043: }
1044:
1045: public static RuntimeException error(String msg, Node node) {
1046: String systemId = null;
1047: String filename = null;
1048: int line = 0;
1049:
1050: if (node instanceof QAbstractNode) {
1051: QAbstractNode qnode = (QAbstractNode) node;
1052:
1053: systemId = qnode.getBaseURI();
1054: filename = qnode.getFilename();
1055: line = qnode.getLine();
1056: }
1057:
1058: if (systemId != null) {
1059: String sourceLines = getSourceLines(systemId, line);
1060:
1061: msg = msg + sourceLines;
1062: }
1063:
1064: if (filename != null)
1065: return new LineConfigException(filename, line, msg);
1066: else
1067: return new LineConfigException(msg);
1068: }
1069:
1070: public static RuntimeException error(Throwable e, Node node) {
1071: String systemId = null;
1072: String filename = null;
1073: int line = 0;
1074:
1075: if (e instanceof RuntimeException
1076: && e instanceof DisplayableException
1077: && !ConfigException.class.equals(e.getClass())) {
1078: return (RuntimeException) e;
1079: }
1080:
1081: if (node instanceof QAbstractNode) {
1082: QAbstractNode qnode = (QAbstractNode) node;
1083:
1084: systemId = qnode.getBaseURI();
1085: filename = qnode.getFilename();
1086: line = qnode.getLine();
1087: }
1088:
1089: for (; e.getCause() != null; e = e.getCause()) {
1090: if (e instanceof LineCompileException)
1091: break;
1092: else if (e instanceof LineConfigException)
1093: break;
1094: else if (e instanceof CompileException)
1095: break;
1096: }
1097:
1098: if (e instanceof LineConfigException)
1099: return (LineConfigException) e;
1100: else if (e instanceof LineCompileException) {
1101: return new LineConfigException(e.getMessage(), e);
1102: } else if (e instanceof ConfigException
1103: && e.getMessage() != null && filename != null) {
1104: String sourceLines = getSourceLines(systemId, line);
1105:
1106: return new LineConfigException(filename, line, e
1107: .getMessage()
1108: + sourceLines, e);
1109: } else if (e instanceof CompileException
1110: && e.getMessage() != null) {
1111: return new LineConfigException(filename, line, e);
1112: } else {
1113: String sourceLines = getSourceLines(systemId, line);
1114:
1115: String msg = filename + ":" + line + ": " + e + sourceLines;
1116:
1117: if (e instanceof RuntimeException) {
1118: throw new LineConfigException(msg, e);
1119: } else if (e instanceof Error) {
1120: // server/1711
1121: throw new LineConfigException(msg, e);
1122: // throw (Error) e;
1123: } else
1124: return new LineConfigException(msg, e);
1125: }
1126: }
1127:
1128: private static String getSourceLines(String systemId, int errorLine) {
1129: if (systemId == null)
1130: return "";
1131:
1132: ReadStream is = null;
1133: try {
1134: is = Vfs.lookup().lookup(systemId).openRead();
1135: int line = 0;
1136: StringBuilder sb = new StringBuilder("\n\n");
1137: String text;
1138: while ((text = is.readLine()) != null) {
1139: line++;
1140:
1141: if (errorLine - 2 <= line && line <= errorLine + 2) {
1142: sb.append(line);
1143: sb.append(": ");
1144: sb.append(text);
1145: sb.append("\n");
1146: }
1147: }
1148:
1149: return sb.toString();
1150: } catch (IOException e) {
1151: log.log(Level.FINEST, e.toString(), e);
1152:
1153: return "";
1154: } finally {
1155: if (is != null)
1156: is.close();
1157: }
1158: }
1159:
1160: public String toString() {
1161: return getClass().getSimpleName() + "[" + _dependentScope + "]";
1162: }
1163:
1164: static class ValidatorEntry {
1165: private Validator _validator;
1166: private ClassLoader _loader;
1167:
1168: ValidatorEntry(Validator validator) {
1169: _validator = validator;
1170:
1171: _loader = Thread.currentThread().getContextClassLoader();
1172: }
1173:
1174: void validate() throws ConfigException {
1175: Thread thread = Thread.currentThread();
1176: ClassLoader oldLoader = thread.getContextClassLoader();
1177:
1178: try {
1179: thread.setContextClassLoader(_loader);
1180:
1181: _validator.validate();
1182: } finally {
1183: thread.setContextClassLoader(oldLoader);
1184: }
1185: }
1186: }
1187:
1188: static {
1189: _resinClassSet.add(RESIN_CLASS_NS);
1190: _resinClassSet.add(RESIN_CLASS);
1191: _resinClassSet.add(RESIN_TYPE_NS);
1192: _resinClassSet.add(RESIN_TYPE);
1193: _resinClassSet.add(new QName("resin:type",
1194: "http://caucho.com/ns/resin"));
1195: _resinClassSet.add(new QName("resin:class",
1196: "http://caucho.com/ns/resin"));
1197: }
1198: }
|