1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.openjpa.lib.ant;
20
21 import java.io.File;
22 import java.security.AccessController;
23 import java.util.ArrayList;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import org.apache.tools.ant.AntClassLoader;
28 import org.apache.tools.ant.BuildException;
29 import org.apache.tools.ant.DirectoryScanner;
30 import org.apache.tools.ant.taskdefs.MatchingTask;
31 import org.apache.tools.ant.types.FileSet;
32 import org.apache.tools.ant.types.Path;
33 import org.apache.openjpa.lib.conf.Configuration;
34 import org.apache.openjpa.lib.conf.ConfigurationImpl;
35 import org.apache.openjpa.lib.conf.ConfigurationProvider;
36 import org.apache.openjpa.lib.conf.ProductDerivations;
37 import org.apache.openjpa.lib.util.J2DoPrivHelper;
38 import org.apache.openjpa.lib.util.Localizer;
39
40 /**
41 * Ant tasks all have a nested <code><config&rt;</code> tag, which uses
42 * the configuration as a bean-like task. E.g., you can do:
43 *
44 * <code>
45 * <mytask&rt;<br />
46 * <config connectionUserName="foo"/&rt;<br />
47 * </mytask&rt;
48 * </code>
49 *
50 * The default configuration for the system will be used if the
51 * <code><config&rt;</code> subtask is excluded.
52 *
53 * @nojavadoc
54 */
55 public abstract class AbstractTask extends MatchingTask {
56
57 private static final Localizer _loc = Localizer.forPackage
58 (AbstractTask.class);
59
60 protected final List fileSets = new ArrayList();
61 protected boolean haltOnError = true;
62 protected Path classpath = null;
63 protected boolean useParent = false;
64 protected boolean isolate = false;
65
66 private ConfigurationImpl _conf = null;
67 private AntClassLoader _cl = null;
68
69 /**
70 * Set whether we want the task to ignore all errors.
71 */
72 public void setHaltOnError(boolean haltOnError) {
73 this.haltOnError = haltOnError;
74 }
75
76 /**
77 * Whether we want the ClassLoader to be isolated from
78 * all other ClassLoaders
79 */
80 public void setIsolate(boolean isolate) {
81 this.isolate = isolate;
82 }
83
84 /**
85 * Whether we want to delegate to the parent ClassLoader
86 * for resolveing classes. This may "taint" classes.
87 */
88 public void setUseParentClassloader(boolean useParent) {
89 this.useParent = useParent;
90 }
91
92 /**
93 * The task configuration.
94 */
95 public Configuration getConfiguration() {
96 if (_conf == null)
97 _conf = newConfiguration();
98 return _conf;
99 }
100
101 /**
102 * Implement this method to return a configuration object for the
103 * product in use.
104 */
105 protected abstract ConfigurationImpl newConfiguration();
106
107 /**
108 * Perform the task action on the given files.
109 */
110 protected abstract void executeOn(String[] files) throws Exception;
111
112 /**
113 * Return the classloader to use.
114 */
115 protected ClassLoader getClassLoader() {
116 if (_cl != null)
117 return _cl;
118
119 if (classpath != null)
120 _cl = new AntClassLoader(project, classpath, useParent);
121 else
122 _cl = new AntClassLoader(project.getCoreLoader(), project,
123 new Path(project), useParent);
124 _cl.setIsolated(isolate);
125
126 return _cl;
127 }
128
129 /**
130 * Helper method to throw a standard exception if the task is not given
131 * any files to execute on. Implementations might call this method as
132 * the first step in {@link #executeOn} to validate that they are given
133 * files to work on.
134 */
135 protected void assertFiles(String[] files) {
136 if (files.length == 0)
137 throw new BuildException(_loc.get("no-filesets").getMessage());
138 }
139
140 public void setClasspath(Path classPath) {
141 createClasspath().append(classPath);
142 }
143
144 public Path createClasspath() {
145 if (classpath == null)
146 classpath = new Path(project);
147 return classpath.createPath();
148 }
149
150 public Object createConfig() {
151 return getConfiguration();
152 }
153
154 public void addFileset(FileSet set) {
155 fileSets.add(set);
156 }
157
158 public void execute() throws BuildException {
159 // if the user didn't supply a conf file, load the default
160 if (_conf == null)
161 _conf = newConfiguration();
162 if (_conf.getPropertiesResource() == null) {
163 ConfigurationProvider cp = ProductDerivations.loadDefaults
164 ((ClassLoader) AccessController.doPrivileged(
165 J2DoPrivHelper.getClassLoaderAction(_conf.getClass())));
166 if (cp != null)
167 cp.setInto(_conf);
168 }
169
170 String[] files = getFiles();
171 try {
172 executeOn(files);
173 } catch (Throwable e) {
174 e.printStackTrace();
175 if (haltOnError)
176 throw new BuildException(e);
177 } finally {
178 _conf.close();
179 _conf = null;
180 }
181 }
182
183 private String[] getFiles() {
184 List files = new ArrayList();
185 for (Iterator i = fileSets.iterator(); i.hasNext();) {
186 FileSet fs = (FileSet) i.next();
187 DirectoryScanner ds = fs.getDirectoryScanner(project);
188
189 String[] dsFiles = ds.getIncludedFiles();
190 for (int j = 0; j < dsFiles.length; j++) {
191 File f = new File(dsFiles[j]);
192 if (!((Boolean) AccessController.doPrivileged(J2DoPrivHelper
193 .isFileAction(f))).booleanValue())
194 f = new File(ds.getBasedir(), dsFiles[j]);
195 files.add((String) AccessController.doPrivileged(
196 J2DoPrivHelper.getAbsolutePathAction(f)));
197 }
198 }
199 return (String[]) files.toArray(new String[files.size()]);
200 }
201 }
202