001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.weaver.ant;
020
021import java.io.File;
022import java.util.Arrays;
023import java.util.List;
024import java.util.Map;
025import java.util.Properties;
026
027import org.apache.commons.lang3.StringUtils;
028import org.apache.tools.ant.BuildException;
029import org.apache.tools.ant.Project;
030import org.apache.tools.ant.types.DataType;
031import org.apache.tools.ant.types.EnumeratedAttribute;
032import org.apache.tools.ant.types.Path;
033import org.apache.tools.ant.types.PropertySet;
034import org.apache.tools.ant.types.Reference;
035import org.apache.tools.ant.types.PropertySet.BuiltinPropertySetName;
036
037/**
038 * Standalone weaver settings datatype. Handles:
039 * <ul>
040 * <li>{@code target} attribute - {@link File}</li>
041 * <li>{@code classpath} attribute - {@link Path} (incompatible with {@code classpathref})</li>
042 * <li>{@code classpathref} attribute - {@link String} (incompatible with {@code classpath})</li>
043 * <li>{@code includeSystemClasspath} attribute - {@code boolean}</li>
044 * <li>nested {@code propertyset} - {@link PropertySet}</li>
045 * <li>nested {@code properties} - {@link InlineProperties}</li>
046 * </ul>
047 * {@code propertyset} and {@code properties} are merged, with the latter taking precedence.
048 */
049public class WeaverSettings extends DataType {
050    private File target;
051    private Path classpath;
052    private String classpathref;
053    private PropertySet propertySet;
054    private InlineProperties inlineProperties;
055    private boolean includeSystemClasspath;
056
057    /**
058     * Create a new {@link WeaverSettings} object.
059     * @param project owner
060     */
061    public WeaverSettings(final Project project) {
062        super();
063        setProject(project);
064    }
065
066    /**
067     * Get the {@code target} directory.
068     * @return {@link File}
069     */
070    public File getTarget() {
071        if (isReference()) {
072            return getRef().getTarget();
073        }
074        return target;
075    }
076
077    /**
078     * Set the {@code target} directory.
079     * @param target {@link File}
080     */
081    public void setTarget(final File target) {
082        if (isReference()) {
083            throw tooManyAttributes();
084        }
085        this.target = target;
086    }
087
088    /**
089     * Get the {@code classpathref}.
090     * @return {@link String}
091     */
092    public String getClasspathref() {
093        if (isReference()) {
094            return getRef().getClasspathref();
095        }
096        return classpathref;
097    }
098
099    /**
100     * Set the {@code classpathref}.
101     * @param classpathref {@link String}
102     */
103    public void setClasspathRef(final String classpathref) {
104        if (isReference()) {
105            throw tooManyAttributes();
106        }
107        this.classpathref = classpathref;
108    }
109
110    /**
111     * Return the effective classpath as a {@link List} of {@link String}
112     * filesystem paths. If {@link #includeSystemClasspath}, system classpath will be appended.
113     * @return List<String>
114     */
115    public List<String> getClasspathEntries() {
116        final Path path = new Path(getProject());
117        final Path classpath = getClasspath();
118        if (classpath != null) {
119            path.add(classpath);
120        }
121        if (includeSystemClasspath) {
122            path.add(Path.systemClasspath);
123        }
124
125        return Arrays.asList(path.list());
126    }
127
128    /**
129     * Get the {@code classpath}.
130     * @return {@link Path}
131     */
132    public Path getClasspath() {
133        if (isReference()) {
134            return getRef().getClasspath();
135        }
136        if (classpath == null) {
137            if (getClasspathref() != null) {
138                final Path ref = new Path(getProject());
139                ref.setRefid(new Reference(getProject(), getClasspathref()));
140                return ref;
141            }
142        } else if (StringUtils.isNotBlank(getClasspathref())) {
143            throw new BuildException("Only one of classpathref|classpath is permitted.");
144        }
145        return classpath;
146    }
147
148    /**
149     * Set the {@code classpath}.
150     * @param classpath {@link Path}
151     */
152    public void setClasspath(final Path classpath) {
153        if (isReference()) {
154            throw tooManyAttributes();
155        }
156        if (this.classpath != null) {
157            throw new BuildException("classpath already set");
158        }
159        this.classpath = classpath;
160    }
161
162    /**
163     * Create the nested {@code properties}.
164     * @return {@link InlineProperties}
165     */
166    public InlineProperties createProperties() {
167        if (isReference()) {
168            throw noChildrenAllowed();
169        }
170        if (inlineProperties != null) {
171            throw new BuildException("properties already specified");
172        }
173        inlineProperties = new InlineProperties();
174        return inlineProperties;
175    }
176
177    /**
178     * Create a nested {@code propertyset}.
179     * @return {@link PropertySet}
180     */
181    public PropertySet createPropertySet() {
182        if (isReference()) {
183            throw noChildrenAllowed();
184        }
185        if (propertySet != null) {
186            throw new BuildException("propertyset already specified");
187        }
188        propertySet = new PropertySet();
189        propertySet.setProject(getProject());
190        return propertySet;
191    }
192
193    /**
194     * Set whether to include the system classpath.
195     * @param includeSystemClasspath the includeSystemClasspath to set
196     * @since 1.3
197     * @see Path#systemClasspath
198     */
199    public void setIncludeSystemClasspath(final boolean includeSystemClasspath) {
200        this.includeSystemClasspath = includeSystemClasspath;
201    }
202
203    /**
204     * Merge nested {@code propertyset} and {@code properties}; latter takes precedence.
205     * @return Properties
206     */
207    public Properties getProperties() {
208        if (isReference()) {
209            return getRef().getProperties();
210        }
211        if (propertySet == null && inlineProperties == null) {
212            createPropertySet().appendBuiltin(
213                (BuiltinPropertySetName) EnumeratedAttribute.getInstance(BuiltinPropertySetName.class, "all"));
214        }
215        final Properties result = new Properties();
216        if (propertySet != null) {
217            result.putAll(propertySet.getProperties());
218        }
219        if (inlineProperties != null) {
220            for (final Map.Entry<Object, Object> entry : inlineProperties.properties.entrySet()) {
221                result.put(entry.getKey(), StringUtils.trim((String) entry.getValue()));
222            }
223        }
224        return result;
225    }
226
227    private WeaverSettings getRef() {
228        return getCheckedRef(WeaverSettings.class, "settings");
229    }
230
231}