Source code: org/objectstyle/cayenne/project/ProjectConfigurator.java
1 /* ====================================================================
2 *
3 * The ObjectStyle Group Software License, Version 1.0
4 *
5 * Copyright (c) 2002-2003 The ObjectStyle Group
6 * and individual authors of the software. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution, if
21 * any, must include the following acknowlegement:
22 * "This product includes software developed by the
23 * ObjectStyle Group (http://objectstyle.org/)."
24 * Alternately, this acknowlegement may appear in the software itself,
25 * if and wherever such third-party acknowlegements normally appear.
26 *
27 * 4. The names "ObjectStyle Group" and "Cayenne"
28 * must not be used to endorse or promote products derived
29 * from this software without prior written permission. For written
30 * permission, please contact andrus@objectstyle.org.
31 *
32 * 5. Products derived from this software may not be called "ObjectStyle"
33 * nor may "ObjectStyle" appear in their names without prior written
34 * permission of the ObjectStyle Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the ObjectStyle Group. For more
52 * information on the ObjectStyle Group, please see
53 * <http://objectstyle.org/>.
54 *
55 */
56 package org.objectstyle.cayenne.project;
57
58 import java.io.File;
59 import java.io.IOException;
60 import java.util.Iterator;
61
62 import org.apache.log4j.Logger;
63 import org.objectstyle.cayenne.conf.Configuration;
64 import org.objectstyle.cayenne.util.Util;
65 import org.objectstyle.cayenne.util.ZipUtil;
66
67 /**
68 * Performs on the fly reconfiguration of Cayenne projects.
69 *
70 * @author Andrei Adamchik
71 */
72 public class ProjectConfigurator {
73 private static Logger logObj = Logger.getLogger(ProjectConfigurator.class);
74 protected ProjectConfigInfo info;
75
76 public ProjectConfigurator(ProjectConfigInfo info) {
77 this.info = info;
78 }
79
80 /**
81 * Performs reconfiguration of the project.
82 *
83 * @throws ProjectException
84 */
85 public void execute() throws ProjectException {
86 File tmpDir = null;
87 File tmpDest = null;
88 try {
89 // initialize default settings
90 if (info.getDestJar() == null) {
91 info.setDestJar(info.getSourceJar());
92 }
93
94 // sanity check
95 validate();
96
97 // do the processing
98 tmpDir = makeTempDirectory();
99 ZipUtil.unzip(info.getSourceJar(), tmpDir);
100
101 reconfigureProject(tmpDir);
102
103 tmpDest = makeTempDestJar();
104 ZipUtil.zip(tmpDest, tmpDir, tmpDir.listFiles(), '/');
105
106 // finally, since everything goes well so far, rename temp file to final name
107 if (info.getDestJar().exists() && !info.getDestJar().delete()) {
108 throw new IOException(
109 "Can't delete old jar file: " + info.getDestJar());
110 }
111
112 if (!tmpDest.renameTo(info.getDestJar())) {
113 throw new IOException(
114 "Error renaming: " + tmpDest + " to " + info.getDestJar());
115 }
116 } catch (IOException ex) {
117 throw new ProjectException("Error performing reconfiguration.", ex);
118 } finally {
119 if (tmpDir != null) {
120 cleanup(tmpDir);
121 }
122
123 if (tmpDest != null) {
124 tmpDest.delete();
125 }
126 }
127 }
128
129 /**
130 * Performs reconfiguration of the unjarred project.
131 *
132 * @param projectDir a directory where a working copy of the project is
133 * located.
134 */
135 protected void reconfigureProject(File projectDir)
136 throws ProjectException {
137 File projectFile = new File(projectDir, Configuration.DEFAULT_DOMAIN_FILE);
138
139 // process alternative project file
140 if (info.getAltProjectFile() != null) {
141 if (!Util.copy(info.getAltProjectFile(), projectFile)) {
142 throw new ProjectException(
143 "Can't copy project file: " + info.getAltProjectFile());
144 }
145 }
146
147 // copy driver files, delete unused
148 Iterator it = info.getNodes().iterator();
149 boolean needFix = it.hasNext();
150 while (it.hasNext()) {
151 DataNodeConfigInfo nodeInfo = (DataNodeConfigInfo) it.next();
152 String name = nodeInfo.getName();
153
154 File targetDriverFile =
155 new File(projectDir, name + DataNodeFile.LOCATION_SUFFIX);
156
157 // these are the two cases when the driver file must be deleted
158 if (nodeInfo.getDataSource() != null
159 || nodeInfo.getDriverFile() != null) {
160 if (targetDriverFile.exists()) {
161 targetDriverFile.delete();
162 }
163 }
164
165 if (nodeInfo.getDriverFile() != null
166 && !nodeInfo.getDriverFile().equals(targetDriverFile)) {
167 // need to copy file from another location
168 if (!Util.copy(nodeInfo.getDriverFile(), targetDriverFile)) {
169 throw new ProjectException(
170 "Can't copy driver file from "
171 + nodeInfo.getDriverFile());
172 }
173 }
174 }
175
176 // load project
177 if (needFix) {
178 // read the project and fix data nodes
179 PartialProject project = new PartialProject(projectFile);
180 project.updateNodes(info.getNodes());
181 project.save();
182 }
183 }
184
185 /**
186 * Returns a temporary file for the destination jar.
187 */
188 protected File makeTempDestJar() throws IOException {
189 File destFolder = info.getDestJar().getParentFile();
190 if (destFolder != null && !destFolder.isDirectory()) {
191 if (!destFolder.mkdirs()) {
192 throw new IOException(
193 "Can't create directory: " + destFolder.getCanonicalPath());
194 }
195 }
196
197 String baseName = "tmp_" + info.getDestJar().getName();
198
199 // seeting upper limit on a number of tries, though normally we would expect
200 // to succeed from the first attempt...
201 for (int i = 0; i < 50; i++) {
202 File tmpFile =
203 (destFolder != null)
204 ? new File(destFolder, baseName + i)
205 : new File(baseName + i);
206 if (!tmpFile.exists()) {
207 return tmpFile;
208 }
209 }
210
211 throw new IOException("Problems creating temporary file.");
212 }
213
214 /**
215 * Deletes a temporary directories and files created.
216 */
217 protected void cleanup(File dir) {
218 if (!Util.delete(dir.getPath(), true)) {
219 logObj.info("Can't delete temporary directory: " + dir);
220 }
221 }
222
223 /**
224 * Creates a temporary directory to unjar the jar file.
225 *
226 * @return File
227 * @throws IOException
228 */
229 protected File makeTempDirectory() throws IOException {
230 File destFolder = info.getDestJar().getParentFile();
231 if (destFolder != null && !destFolder.isDirectory()) {
232 if (!destFolder.mkdirs()) {
233 throw new IOException(
234 "Can't create directory: " + destFolder.getCanonicalPath());
235 }
236 }
237
238 String baseName = info.getDestJar().getName();
239 if (baseName.endsWith(".jar")) {
240 baseName = baseName.substring(0, baseName.length() - 4);
241 }
242
243 // seeting upper limit on a number of tries, though normally we would expect
244 // to succeed from the first attempt...
245 for (int i = 0; i < 50; i++) {
246 File tmpDir =
247 (destFolder != null)
248 ? new File(destFolder, baseName + i)
249 : new File(baseName + i);
250 if (!tmpDir.exists()) {
251 if (!tmpDir.mkdir()) {
252 throw new IOException(
253 "Can't create directory: " + tmpDir.getCanonicalPath());
254 }
255
256 return tmpDir;
257 }
258 }
259
260 throw new IOException("Problems creating temporary directory.");
261 }
262
263 /**
264 * Validates consistency of the reconfiguration information.
265 */
266 protected void validate() throws IOException, ProjectException {
267 if (info == null) {
268 throw new ProjectException("ProjectConfig info is not set.");
269 }
270
271 if (info.getSourceJar() == null) {
272 throw new ProjectException("Source jar file is not set.");
273 }
274
275 if (!info.getSourceJar().isFile()) {
276 throw new IOException(info.getSourceJar() + " is not a file.");
277 }
278
279 if (!info.getSourceJar().canRead()) {
280 throw new IOException("Can't read file: " + info.getSourceJar());
281 }
282 }
283 }