001: /*
002: /*
003: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
004: *
005: * http://izpack.org/
006: * http://izpack.codehaus.org/
007: *
008: * Copyright 2002 Marcus Wolschon
009: * Copyright 2002 Jan Blok
010: * Copyright 2004 Klaus Bartz
011: *
012: * Licensed under the Apache License, Version 2.0 (the "License");
013: * you may not use this file except in compliance with the License.
014: * You may obtain a copy of the License at
015: *
016: * http://www.apache.org/licenses/LICENSE-2.0
017: *
018: * Unless required by applicable law or agreed to in writing, software
019: * distributed under the License is distributed on an "AS IS" BASIS,
020: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
021: * See the License for the specific language governing permissions and
022: * limitations under the License.
023: */
024: package com.izforge.izpack.ant;
025:
026: import java.util.Enumeration;
027: import java.util.Vector;
028:
029: import org.apache.tools.ant.BuildException;
030: import org.apache.tools.ant.Project;
031:
032: /**
033: * A nested element holder for the installation configuration document content.
034: * The installation document must be passed in using a CDATA element.
035: *
036: * @author Scott Stark
037: * @version $Revision: 2056 $
038: */
039: public class ConfigHolder {
040: /** The parent element project */
041: private Project project;
042:
043: /** The config element body text with ${x} property references replaced */
044: private String installText;
045:
046: /**
047: * Taken from the ant org.apache.tools.ant.PropertyHelper and '$' replaced
048: * with '@' to deal with @{x} style property references.
049: *
050: * Parses a string containing @{xxx} style property references
051: * into two lists. The first list is a collection of text fragments, while
052: * the other is a set of string property names. null entries in the
053: * first list indicate a property reference from the second list.
054: *
055: * It can be overridden with a more efficient or customized version.
056: *
057: * @param value Text to parse. Must not be null.
058: * @param fragments List to add text fragments to. Must not be null.
059: * @param propertyRefs List to add property names to. Must not be null.
060: *
061: * @exception BuildException if the string contains an opening @{ without a
062: * closing }
063: */
064: static void parseCompileProperties(String value,
065: Vector<String> fragments, Vector<String> propertyRefs)
066: throws BuildException {
067: int prev = 0;
068: int pos;
069: // search for the next instance of $ from the 'prev' position
070: while ((pos = value.indexOf("@", prev)) >= 0) {
071:
072: // if there was any text before this, add it as a fragment
073: // TODO, this check could be modified to go if pos>prev;
074: // seems like this current version could stick empty strings
075: // into the list
076: if (pos > 0) {
077: fragments.addElement(value.substring(prev, pos));
078: }
079: // if we are at the end of the string, we tack on a $
080: // then move past it
081: if (pos == (value.length() - 1)) {
082: fragments.addElement("@");
083: prev = pos + 1;
084: } else if (value.charAt(pos + 1) != '{') {
085: // peek ahead to see if the next char is a property or not
086: // not a property: insert the char as a literal
087: /*
088: * fragments.addElement(value.substring(pos + 1, pos + 2)); prev = pos + 2;
089: */
090: if (value.charAt(pos + 1) == '@') {
091: // backwards compatibility two $ map to one mode
092: fragments.addElement("@");
093: prev = pos + 2;
094: } else {
095: // new behaviour: $X maps to $X for all values of X!='$'
096: fragments.addElement(value.substring(pos, pos + 2));
097: prev = pos + 2;
098: }
099:
100: } else {
101: // property found, extract its name or bail on a typo
102: int endName = value.indexOf('}', pos);
103: if (endName < 0) {
104: throw new BuildException(
105: "Syntax error in property: " + value);
106: }
107: String propertyName = value.substring(pos + 2, endName);
108: fragments.addElement(null);
109: propertyRefs.addElement(propertyName);
110: prev = endName + 1;
111: }
112: }
113: // no more @ signs found
114: // if there is any tail to the file, append it
115: if (prev < value.length()) {
116: fragments.addElement(value.substring(prev));
117: }
118: }
119:
120: ConfigHolder(Project project) {
121: this .project = project;
122: }
123:
124: /**
125: * Called by ant to set the config element content. The content is scanned
126: * for @{x} style property references and replaced with the x project
127: * property.
128: *
129: * @param rawText - the raw config element body text.
130: */
131: public void addText(String rawText) {
132: // Locate the @{x} references
133: Vector<String> fragments = new Vector<String>();
134: Vector<String> propertyRefs = new Vector<String>();
135: parseCompileProperties(rawText, fragments, propertyRefs);
136:
137: // Replace the references with the project property value
138: StringBuffer sb = new StringBuffer();
139: Enumeration<String> i = fragments.elements();
140: Enumeration<String> j = propertyRefs.elements();
141:
142: while (i.hasMoreElements()) {
143: String fragment = i.nextElement();
144: if (fragment == null) {
145: String propertyName = j.nextElement();
146: Object replacement = null;
147:
148: // try to get it from the project
149: if (replacement == null) {
150: replacement = project.getProperty(propertyName);
151: }
152:
153: if (replacement == null) {
154: project
155: .log("Property @{" + propertyName
156: + "} has not been set",
157: Project.MSG_VERBOSE);
158: }
159: if (replacement != null)
160: fragment = replacement.toString();
161: else
162: fragment = "@{" + propertyName + "}";
163: }
164: sb.append(fragment);
165: }
166:
167: installText = sb.toString();
168: }
169:
170: /**
171: * Get the config element body text with @{x} property references replaced
172: *
173: * @return the processed config element body text.
174: */
175: public String getText() {
176: return installText;
177: }
178:
179: }
|