aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java726
1 files changed, 726 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java
new file mode 100644
index 00000000..162cab1a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java
@@ -0,0 +1,726 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.LayoutPreservingProperties;
+
+/**
+ * Modifies settings in a property file.
+ *
+ * <p>The following is an example of its usage:</p>
+ * <pre>
+ * &lt;target name="setState"&gt;
+ * &lt;property
+ * name="header"
+ * value="##Generated file - do not modify!"/&gt;
+ * &lt;propertyfile file="apropfile.properties" comment="${header}"&gt;
+ * &lt;entry key="product.version.major" type="int" value="5"/&gt;
+ * &lt;entry key="product.version.minor" type="int" value="0"/&gt;
+ * &lt;entry key="product.build.major" type="int" value="0" /&gt;
+ * &lt;entry key="product.build.minor" type="int" operation="+" /&gt;
+ * &lt;entry key="product.build.date" type="date" value="now" /&gt;
+ * &lt;entry key="intSet" type="int" operation="=" value="681"/&gt;
+ * &lt;entry key="intDec" type="int" operation="-"/&gt;
+ * &lt;entry key="StringEquals" type="string" value="testValue"/&gt;
+ * &lt;/propertyfile&gt;
+ * &lt;/target&gt;
+ * </pre>
+ *
+ * The &lt;propertyfile&gt; task must have:
+ * <ul>
+ * <li>file</li>
+ * </ul>
+ * Other parameters are:
+ * <ul>
+ * <li>comment</li>
+ * <li>key</li>
+ * <li>operation</li>
+ * <li>type</li>
+ * <li>value (the final four being eliminated shortly)</li>
+ * </ul>
+ *
+ * The &lt;entry&gt; task must have:
+ * <ul>
+ * <li>key</li>
+ * </ul>
+ * Other parameters are:
+ * <ul>
+ * <li>operation</li>
+ * <li>type</li>
+ * <li>value</li>
+ * <li>default</li>
+ * <li>unit</li>
+ * </ul>
+ *
+ * If type is unspecified, it defaults to string.
+ *
+ * Parameter values:
+ * <ul>
+ * <li>operation:</li>
+ * <ul>
+ * <li>"=" (set -- default)</li>
+ * <li>"-" (dec)</li>
+ * <li>"+" (inc)</li>
+ * </ul>
+ * <li>type:</li>
+ * <ul>
+ * <li>"int"</li>
+ * <li>"date"</li>
+ * <li>"string"</li>
+ * </ul>
+ * <li>value:</li>
+ * <ul>
+ * <li>holds the default value, if the property
+ * was not found in property file</li>
+ * <li>"now" In case of type "date", the
+ * value "now" will be replaced by the current
+ * date/time and used even if a valid date was
+ * found in the property file.</li>
+ * </ul>
+ * </ul>
+ *
+ * <p>String property types can only use the "=" operation.
+ * Int property types can only use the "=", "-" or "+" operations.<p>
+ *
+ * The message property is used for the property file header, with "\\" being
+ * a newline delimiter character.
+ *
+ */
+public class PropertyFile extends Task {
+
+ /* ========================================================================
+ *
+ * Instance variables.
+ */
+
+ // Use this to prepend a message to the properties file
+ private String comment;
+
+ private Properties properties;
+ private File propertyfile;
+ private boolean useJDKProperties;
+
+ private Vector entries = new Vector();
+
+ /* ========================================================================
+ *
+ * Constructors
+ */
+
+ /* ========================================================================
+ *
+ * Methods
+ */
+
+ /**
+ * Execute the task.
+ * @throws BuildException on error.
+ */
+ @Override
+ public void execute() throws BuildException {
+ checkParameters();
+ readFile();
+ executeOperation();
+ writeFile();
+ }
+
+ /**
+ * The entry nested element.
+ * @return an entry nested element to be configured.
+ */
+ public Entry createEntry() {
+ Entry e = new Entry();
+ entries.addElement(e);
+ return e;
+ }
+
+ private void executeOperation() throws BuildException {
+ for (Enumeration e = entries.elements(); e.hasMoreElements();) {
+ Entry entry = (Entry) e.nextElement();
+ entry.executeOn(properties);
+ }
+ }
+
+ private void readFile() throws BuildException {
+ if (useJDKProperties) {
+ // user chose to use standard Java properties, which loose
+ // comments and layout
+ properties = new Properties();
+ } else {
+ properties = new LayoutPreservingProperties();
+ }
+ try {
+ if (propertyfile.exists()) {
+ log("Updating property file: "
+ + propertyfile.getAbsolutePath());
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(propertyfile);
+ BufferedInputStream bis = new BufferedInputStream(fis);
+ properties.load(bis);
+ } finally {
+ if (fis != null) {
+ fis.close();
+ }
+ }
+ } else {
+ log("Creating new property file: "
+ + propertyfile.getAbsolutePath());
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(propertyfile.getAbsolutePath());
+ out.flush();
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+ } catch (IOException ioe) {
+ throw new BuildException(ioe.toString());
+ }
+ }
+
+ private void checkParameters() throws BuildException {
+ if (!checkParam(propertyfile)) {
+ throw new BuildException("file token must not be null.",
+ getLocation());
+ }
+ }
+
+ /**
+ * Location of the property file to be edited; required.
+ * @param file the property file.
+ */
+ public void setFile(File file) {
+ propertyfile = file;
+ }
+
+ /**
+ * optional header comment for the file
+ * @param hdr the string to use for the comment.
+ */
+ public void setComment(String hdr) {
+ comment = hdr;
+ }
+
+ /**
+ * optional flag to use original Java properties (as opposed to
+ * layout preserving properties)
+ */
+ public void setJDKProperties(boolean val) {
+ useJDKProperties = val;
+ }
+
+ private void writeFile() throws BuildException {
+ // Write to RAM first, as an OOME could otherwise produce a truncated file:
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ properties.store(baos, comment);
+ } catch (IOException x) { // should not happen
+ throw new BuildException(x, getLocation());
+ }
+ try {
+ OutputStream os = new FileOutputStream(propertyfile);
+ try {
+ try {
+ os.write(baos.toByteArray());
+ } finally {
+ os.close();
+ }
+ } catch (IOException x) { // possibly corrupt
+ FileUtils.getFileUtils().tryHardToDelete(propertyfile);
+ throw x;
+ }
+ } catch (IOException x) { // opening, writing, or closing
+ throw new BuildException(x, getLocation());
+ }
+ }
+
+ private boolean checkParam(File param) {
+ return !(param == null);
+ }
+
+ /**
+ * Instance of this class represents nested elements of
+ * a task propertyfile.
+ */
+ public static class Entry {
+ private static final int DEFAULT_INT_VALUE = 0;
+ private static final String DEFAULT_DATE_VALUE = "now";
+ private static final String DEFAULT_STRING_VALUE = "";
+
+ private String key = null;
+ private int type = Type.STRING_TYPE;
+ private int operation = Operation.EQUALS_OPER;
+ private String value = null;
+ private String defaultValue = null;
+ private String newValue = null;
+ private String pattern = null;
+ private int field = Calendar.DATE;
+
+ /**
+ * Name of the property name/value pair
+ * @param value the key.
+ */
+ public void setKey(String value) {
+ this.key = value;
+ }
+
+ /**
+ * Value to set (=), to add (+) or subtract (-)
+ * @param value the value.
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ /**
+ * operation to apply.
+ * &quot;+&quot; or &quot;=&quot;
+ *(default) for all datatypes; &quot;-&quot; for date and int only)\.
+ * @param value the operation enumerated value.
+ */
+ public void setOperation(Operation value) {
+ this.operation = Operation.toOperation(value.getValue());
+ }
+
+ /**
+ * Regard the value as : int, date or string (default)
+ * @param value the type enumerated value.
+ */
+ public void setType(Type value) {
+ this.type = Type.toType(value.getValue());
+ }
+
+ /**
+ * Initial value to set for a property if it is not
+ * already defined in the property file.
+ * For type date, an additional keyword is allowed: &quot;now&quot;
+ * @param value the default value.
+ */
+ public void setDefault(String value) {
+ this.defaultValue = value;
+ }
+
+ /**
+ * For int and date type only. If present, Values will
+ * be parsed and formatted accordingly.
+ * @param value the pattern to use.
+ */
+ public void setPattern(String value) {
+ this.pattern = value;
+ }
+
+ /**
+ * The unit of the value to be applied to date +/- operations.
+ * Valid Values are:
+ * <ul>
+ * <li>millisecond</li>
+ * <li>second</li>
+ * <li>minute</li>
+ * <li>hour</li>
+ * <li>day (default)</li>
+ * <li>week</li>
+ * <li>month</li>
+ * <li>year</li>
+ * </ul>
+ * This only applies to date types using a +/- operation.
+ * @param unit the unit enumerated value.
+ * @since Ant 1.5
+ */
+ public void setUnit(PropertyFile.Unit unit) {
+ field = unit.getCalendarField();
+ }
+
+ /**
+ * Apply the nested element to the properties.
+ * @param props the properties to apply the entry on.
+ * @throws BuildException if there is an error.
+ */
+ protected void executeOn(Properties props) throws BuildException {
+ checkParameters();
+
+ if (operation == Operation.DELETE_OPER) {
+ props.remove(key);
+ return;
+ }
+
+ // type may be null because it wasn't set
+ String oldValue = (String) props.get(key);
+ try {
+ if (type == Type.INTEGER_TYPE) {
+ executeInteger(oldValue);
+ } else if (type == Type.DATE_TYPE) {
+ executeDate(oldValue);
+ } else if (type == Type.STRING_TYPE) {
+ executeString(oldValue);
+ } else {
+ throw new BuildException("Unknown operation type: "
+ + type);
+ }
+ } catch (NullPointerException npe) {
+ // Default to string type
+ // which means do nothing
+ npe.printStackTrace();
+ }
+
+ if (newValue == null) {
+ newValue = "";
+ }
+
+ // Insert as a string by default
+ props.put(key, newValue);
+ }
+
+ /**
+ * Handle operations for type <code>date</code>.
+ *
+ * @param oldValue the current value read from the property file or
+ * <code>null</code> if the <code>key</code> was
+ * not contained in the property file.
+ */
+ private void executeDate(String oldValue) throws BuildException {
+ Calendar currentValue = Calendar.getInstance();
+
+ if (pattern == null) {
+ pattern = "yyyy/MM/dd HH:mm";
+ }
+ DateFormat fmt = new SimpleDateFormat(pattern);
+
+ String currentStringValue = getCurrentValue(oldValue);
+ if (currentStringValue == null) {
+ currentStringValue = DEFAULT_DATE_VALUE;
+ }
+
+ if ("now".equals(currentStringValue)) {
+ currentValue.setTime(new Date());
+ } else {
+ try {
+ currentValue.setTime(fmt.parse(currentStringValue));
+ } catch (ParseException pe) {
+ // swallow
+ }
+ }
+
+ if (operation != Operation.EQUALS_OPER) {
+ int offset = 0;
+ try {
+ offset = Integer.parseInt(value);
+ if (operation == Operation.DECREMENT_OPER) {
+ offset = -1 * offset;
+ }
+ } catch (NumberFormatException e) {
+ throw new BuildException("Value not an integer on " + key);
+ }
+ currentValue.add(field, offset);
+ }
+
+ newValue = fmt.format(currentValue.getTime());
+ }
+
+
+ /**
+ * Handle operations for type <code>int</code>.
+ *
+ * @param oldValue the current value read from the property file or
+ * <code>null</code> if the <code>key</code> was
+ * not contained in the property file.
+ */
+ private void executeInteger(String oldValue) throws BuildException {
+ int currentValue = DEFAULT_INT_VALUE;
+ int newV = DEFAULT_INT_VALUE;
+
+
+ DecimalFormat fmt = (pattern != null) ? new DecimalFormat(pattern)
+ : new DecimalFormat();
+ try {
+ String curval = getCurrentValue(oldValue);
+ if (curval != null) {
+ currentValue = fmt.parse(curval).intValue();
+ } else {
+ currentValue = 0;
+ }
+ } catch (NumberFormatException nfe) {
+ // swallow
+ } catch (ParseException pe) {
+ // swallow
+ }
+
+ if (operation == Operation.EQUALS_OPER) {
+ newV = currentValue;
+ } else {
+ int operationValue = 1;
+ if (value != null) {
+ try {
+ operationValue = fmt.parse(value).intValue();
+ } catch (NumberFormatException nfe) {
+ // swallow
+ } catch (ParseException pe) {
+ // swallow
+ }
+ }
+
+ if (operation == Operation.INCREMENT_OPER) {
+ newV = currentValue + operationValue;
+ } else if (operation == Operation.DECREMENT_OPER) {
+ newV = currentValue - operationValue;
+ }
+ }
+
+ this.newValue = fmt.format(newV);
+ }
+
+ /**
+ * Handle operations for type <code>string</code>.
+ *
+ * @param oldValue the current value read from the property file or
+ * <code>null</code> if the <code>key</code> was
+ * not contained in the property file.
+ */
+ private void executeString(String oldValue) throws BuildException {
+ String newV = DEFAULT_STRING_VALUE;
+
+ String currentValue = getCurrentValue(oldValue);
+
+ if (currentValue == null) {
+ currentValue = DEFAULT_STRING_VALUE;
+ }
+
+ if (operation == Operation.EQUALS_OPER) {
+ newV = currentValue;
+ } else if (operation == Operation.INCREMENT_OPER) {
+ newV = currentValue + value;
+ }
+ this.newValue = newV;
+ }
+
+ /**
+ * Check if parameter combinations can be supported
+ * @todo make sure the 'unit' attribute is only specified on date
+ * fields
+ */
+ private void checkParameters() throws BuildException {
+ if (type == Type.STRING_TYPE
+ && operation == Operation.DECREMENT_OPER) {
+ throw new BuildException("- is not supported for string "
+ + "properties (key:" + key + ")");
+ }
+ if (value == null && defaultValue == null && operation != Operation.DELETE_OPER) {
+ throw new BuildException("\"value\" and/or \"default\" "
+ + "attribute must be specified (key:" + key + ")");
+ }
+ if (key == null) {
+ throw new BuildException("key is mandatory");
+ }
+ if (type == Type.STRING_TYPE && pattern != null) {
+ throw new BuildException("pattern is not supported for string "
+ + "properties (key:" + key + ")");
+ }
+ }
+
+ private String getCurrentValue(String oldValue) {
+ String ret = null;
+ if (operation == Operation.EQUALS_OPER) {
+ // If only value is specified, the property is set to it
+ // regardless of its previous value.
+ if (value != null && defaultValue == null) {
+ ret = value;
+ }
+
+ // If only default is specified and the property previously
+ // existed in the property file, it is unchanged.
+ if (value == null && defaultValue != null && oldValue != null) {
+ ret = oldValue;
+ }
+
+ // If only default is specified and the property did not
+ // exist in the property file, the property is set to default.
+ if (value == null && defaultValue != null && oldValue == null) {
+ ret = defaultValue;
+ }
+
+ // If value and default are both specified and the property
+ // previously existed in the property file, the property
+ // is set to value.
+ if (value != null && defaultValue != null && oldValue != null) {
+ ret = value;
+ }
+
+ // If value and default are both specified and the property
+ // did not exist in the property file, the property is set
+ // to default.
+ if (value != null && defaultValue != null && oldValue == null) {
+ ret = defaultValue;
+ }
+ } else {
+ ret = (oldValue == null) ? defaultValue : oldValue;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Enumerated attribute with the values "+", "-", "="
+ */
+ public static class Operation extends EnumeratedAttribute {
+
+ // Property type operations
+ /** + */
+ public static final int INCREMENT_OPER = 0;
+ /** - */
+ public static final int DECREMENT_OPER = 1;
+ /** = */
+ public static final int EQUALS_OPER = 2;
+ /** del */
+ public static final int DELETE_OPER = 3;
+
+ /** {@inheritDoc}. */
+ @Override
+ public String[] getValues() {
+ return new String[] {"+", "-", "=", "del"};
+ }
+
+ /**
+ * Convert string to index.
+ * @param oper the string to convert.
+ * @return the index.
+ */
+ public static int toOperation(String oper) {
+ if ("+".equals(oper)) {
+ return INCREMENT_OPER;
+ } else if ("-".equals(oper)) {
+ return DECREMENT_OPER;
+ } else if ("del".equals(oper)) {
+ return DELETE_OPER;
+ }
+ return EQUALS_OPER;
+ }
+ }
+
+ /**
+ * Enumerated attribute with the values "int", "date" and "string".
+ */
+ public static class Type extends EnumeratedAttribute {
+
+ // Property types
+ /** int */
+ public static final int INTEGER_TYPE = 0;
+ /** date */
+ public static final int DATE_TYPE = 1;
+ /** string */
+ public static final int STRING_TYPE = 2;
+
+ /** {@inheritDoc} */
+ @Override
+ public String[] getValues() {
+ return new String[] {"int", "date", "string"};
+ }
+
+ /**
+ * Convert string to index.
+ * @param type the string to convert.
+ * @return the index.
+ */
+ public static int toType(String type) {
+ if ("int".equals(type)) {
+ return INTEGER_TYPE;
+ } else if ("date".equals(type)) {
+ return DATE_TYPE;
+ }
+ return STRING_TYPE;
+ }
+ }
+ }
+
+ /**
+ * Borrowed from Tstamp
+ * @todo share all this time stuff across many tasks as a datetime datatype
+ * @since Ant 1.5
+ */
+ public static class Unit extends EnumeratedAttribute {
+
+ private static final String MILLISECOND = "millisecond";
+ private static final String SECOND = "second";
+ private static final String MINUTE = "minute";
+ private static final String HOUR = "hour";
+ private static final String DAY = "day";
+ private static final String WEEK = "week";
+ private static final String MONTH = "month";
+ private static final String YEAR = "year";
+
+ private static final String[] UNITS
+ = {MILLISECOND, SECOND, MINUTE, HOUR,
+ DAY, WEEK, MONTH, YEAR };
+
+ private Map calendarFields = new HashMap();
+
+ /** no arg constructor */
+ public Unit() {
+ calendarFields.put(MILLISECOND,
+ new Integer(Calendar.MILLISECOND));
+ calendarFields.put(SECOND, new Integer(Calendar.SECOND));
+ calendarFields.put(MINUTE, new Integer(Calendar.MINUTE));
+ calendarFields.put(HOUR, new Integer(Calendar.HOUR_OF_DAY));
+ calendarFields.put(DAY, new Integer(Calendar.DATE));
+ calendarFields.put(WEEK, new Integer(Calendar.WEEK_OF_YEAR));
+ calendarFields.put(MONTH, new Integer(Calendar.MONTH));
+ calendarFields.put(YEAR, new Integer(Calendar.YEAR));
+ }
+
+ /**
+ * Convert the value to a Calendar field index.
+ * @return the calendar value.
+ */
+ public int getCalendarField() {
+ String key = getValue().toLowerCase();
+ Integer i = (Integer) calendarFields.get(key);
+ return i.intValue();
+ }
+
+ /** {@inheritDoc}. */
+ @Override
+ public String[] getValues() {
+ return UNITS;
+ }
+ }
+}