001: package org.apache.velocity.tools.view;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.io.File;
023: import java.io.FileInputStream;
024: import java.io.InputStream;
025: import java.util.ArrayList;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Map;
030:
031: import org.apache.commons.digester.Digester;
032: import org.apache.commons.digester.RuleSet;
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035:
036: /**
037: * A ToolboxManager for loading a toolbox from xml.
038: *
039: * <p>A toolbox manager is responsible for automatically filling the Velocity
040: * context with a set of view tools. This class provides the following
041: * features:</p>
042: * <ul>
043: * <li>configurable through an XML-based configuration file</li>
044: * <li>assembles a set of view tools (the toolbox) on request</li>
045: * <li>supports any class with a public constructor without parameters
046: * to be used as a view tool</li>
047: * <li>supports adding primitive data values to the context(String,Number,Boolean)</li>
048: * </ul>
049: *
050: *
051: * <p><strong>Configuration</strong></p>
052: * <p>The toolbox manager is configured through an XML-based configuration
053: * file. The configuration file is passed to the {@link #load(java.io.InputStream input)}
054: * method. The format is shown in the following example:</p>
055: * <pre>
056: * <?xml version="1.0"?>
057: * <toolbox>
058: * <tool>
059: * <key>date</key>
060: * <class>org.apache.velocity.tools.generic.DateTool</class>
061: * </tool>
062: * <data type="Number">
063: * <key>luckynumber</key>
064: * <value>1.37</value>
065: * </data>
066: * <data type="String">
067: * <key>greeting</key>
068: * <value>Hello World!</value>
069: * </data>
070: * </toolbox>
071: * </pre>
072: *
073: *
074: * @author Nathan Bubna
075: * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
076: * @author <a href="mailto:henning@schmiedehausen.org">Henning P. Schmiedehausen</a>
077: * @version $Id: XMLToolboxManager.java 479724 2006-11-27 18:49:37Z nbubna $
078: */
079: public class XMLToolboxManager implements ToolboxManager {
080: protected static final Log LOG = LogFactory
081: .getLog(XMLToolboxManager.class);
082:
083: private List toolinfo;
084: private Map data;
085:
086: private static RuleSet ruleSet = new ToolboxRuleSet();
087:
088: /**
089: * Default constructor
090: */
091: public XMLToolboxManager() {
092: toolinfo = new ArrayList();
093: data = new HashMap();
094: }
095:
096: // ------------------------------- ToolboxManager interface ------------
097:
098: public void addTool(ToolInfo info) {
099: System.out.println("addTool(" + info);
100: if (validateToolInfo(info)) {
101: toolinfo.add(info);
102: if (LOG.isDebugEnabled()) {
103: LOG.debug("Added " + info.getClassname()
104: + " to the toolbox as " + info.getKey());
105: }
106: }
107: }
108:
109: public void addData(ToolInfo info) {
110: if (validateToolInfo(info)) {
111: data.put(info.getKey(), info.getInstance(null));
112: if (LOG.isDebugEnabled()) {
113: LOG.debug("Added '" + info.getInstance(null)
114: + "' to the toolbox as " + info.getKey());
115: }
116: }
117: }
118:
119: /**
120: * Checks whether an object described by a ToolInfo passes
121: * some basic sanity checks.
122: *
123: * @param info A ToolInfo object
124: *
125: * @return true if the ToolInfo is valid
126: */
127: protected boolean validateToolInfo(ToolInfo info) {
128: if (info == null) {
129: LOG.error("ToolInfo is null!");
130: return false;
131: }
132: if (info.getKey() == null || info.getKey().length() == 0) {
133: LOG.error("Tool has no key defined!");
134: return false;
135: }
136: if (info.getClassname() == null) {
137: LOG.error("Tool " + info.getKey()
138: + " has no Class definition!");
139: return false;
140: }
141: return true;
142: }
143:
144: public Map getToolbox(Object initData) {
145: Map toolbox = new HashMap(data);
146: Iterator i = toolinfo.iterator();
147: while (i.hasNext()) {
148: ToolInfo info = (ToolInfo) i.next();
149: toolbox.put(info.getKey(), info.getInstance(initData));
150: }
151: return toolbox;
152: }
153:
154: // ------------------------------- toolbox loading methods ------------
155:
156: /**
157: * <p>Reads an XML document from the specified file path
158: * and sets up the toolbox from that. If the file does not
159: * exist, an {@link IllegalArgumentException} will be thrown.</p>
160: *
161: * @param path the path to the file to be read from
162: * @since VelocityTools 1.3
163: */
164: public void load(String path) throws Exception {
165: if (path == null) {
166: throw new IllegalArgumentException(
167: "Path value cannot be null");
168: }
169:
170: File file = new File(path);
171: if (!file.exists()) {
172: throw new IllegalArgumentException(
173: "Could not find toolbox config file at: " + path);
174: }
175:
176: // ok, load the file
177: load(new FileInputStream(file));
178: }
179:
180: /**
181: * <p>Reads an XML document from an {@link InputStream}
182: * and sets up the toolbox from that.</p>
183: *
184: * @param input the InputStream to read from
185: */
186: public void load(InputStream input) throws Exception {
187: LOG.trace("Loading toolbox...");
188:
189: Digester digester = new Digester();
190: digester.setValidating(false);
191: digester.setUseContextClassLoader(true);
192: digester.push(this );
193: digester.addRuleSet(getRuleSet());
194: digester.parse(input);
195:
196: LOG.trace("Toolbox loaded.");
197: }
198:
199: /**
200: * <p>Retrieves the rule set Digester should use to parse and load
201: * the toolbox for this manager.</p>
202: *
203: * <p>The DTD corresponding to the default ToolboxRuleSet is:
204: * <pre>
205: * <?xml version="1.0"?>
206: * <!ELEMENT toolbox (tool*,data*,#PCDATA)>
207: * <!ELEMENT tool (key,class,parameter*,#PCDATA)>
208: * <!ELEMENT data (key,value)>
209: * <!ATTLIST data type (string|number|boolean) "string">
210: * <!ELEMENT key (#CDATA)>
211: * <!ELEMENT class (#CDATA)>
212: * <!ELEMENT parameter (EMPTY)>
213: * <!ATTLIST parameter name CDATA #REQUIRED>
214: * <!ATTLIST parameter value CDATA #REQUIRED>
215: * <!ELEMENT value (#CDATA)>
216: * </pre></p>
217: *
218: * @since VelocityTools 1.1
219: */
220: protected RuleSet getRuleSet() {
221: return ruleSet;
222: }
223:
224: }
|