1 /*
2 * Copyright 2003 - 2013 The eFaps Team
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Revision: $Rev$
17 * Last Changed: $Date$
18 * Last Changed By: $Author$
19 */
20
21 package org.efaps.update.schema.program;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.io.Reader;
28 import java.io.UnsupportedEncodingException;
29 import java.net.URL;
30 import java.util.UUID;
31
32 import org.efaps.ci.CIAdminProgram;
33 import org.efaps.ci.CIType;
34 import org.efaps.db.Checkin;
35 import org.efaps.db.Insert;
36 import org.efaps.db.Instance;
37 import org.efaps.db.InstanceQuery;
38 import org.efaps.db.QueryBuilder;
39 import org.efaps.update.util.InstallationException;
40 import org.efaps.util.EFapsException;
41
42 /**
43 * Class used to import programs into eFaps.
44 *
45 * @author The eFaps Team
46 * @version $Id$
47 */
48 public abstract class AbstractSourceImporter
49 {
50 /**
51 * Defines the encoding of source code within eFaps.
52 *
53 * @see #readCode()
54 * @see #newCodeInputStream()
55 */
56 protected static final String ENCODING = "UTF8";
57
58 /**
59 * URL of the source file in file system (or in jar, ...).
60 */
61 private final URL url;
62
63 /**
64 * Source code itself.
65 */
66 private final StringBuilder code = new StringBuilder();
67
68 /**
69 * eFaps UUID of the program.
70 */
71 private final UUID eFapsUUID;
72
73 /**
74 * eFaps revision of the program.
75 */
76 private final String revision;
77
78 /**
79 * Name of the program in eFaps.
80 *
81 * @see #getClassName
82 */
83 private final String programName;
84
85 /**
86 * CIType.
87 */
88 private final CIType ciType;
89
90 /**
91 * Constructor used to read the source code from given URL and extract the
92 * class name.
93 *
94 * @param _type related eFaps type
95 * @param _url URL to the source code
96 * @throws InstallationException on error
97 * @see #readCode()
98 * @see #evalProgramName()
99 * @see #evalUUID()
100 * @see #evalRevision()
101 */
102 public AbstractSourceImporter(final CIType _type,
103 final URL _url)
104 throws InstallationException
105 {
106 this.ciType = _type;
107 this.url = _url;
108 readCode();
109 this.programName = evalProgramName();
110 this.eFapsUUID = evalUUID();
111 this.revision = evalRevision();
112 }
113
114 /**
115 * Read the code from the file defined through {@link #url} with character
116 * set {@link #ENCODING}.
117 *
118 * @throws InstallationException if the source code could not read from URL
119 * @see #url
120 * @see #ENCODING
121 */
122 protected void readCode()
123 throws InstallationException
124 {
125 try {
126 final char[] buf = new char[1024];
127
128 final InputStream input = getUrl().openStream();
129
130 final Reader reader = new InputStreamReader(input, AbstractSourceImporter.ENCODING);
131 int length;
132 while ((length = reader.read(buf)) > 0) {
133 this.code.append(buf, 0, length);
134 }
135 reader.close();
136 } catch (final IOException e) {
137 throw new InstallationException("Could not read source code from url '" + this.url + "'.", e);
138 }
139 }
140
141 /**
142 * This Method extracts the Name from the program.
143 *
144 * @return Name of the program
145 * @throws InstallationException on error
146 */
147 protected abstract String evalProgramName()
148 throws InstallationException;
149
150 /**
151 * This Method extracts the UUID from the program.
152 *
153 * @return UUID of the program
154 * @throws InstallationException on error
155 */
156 protected abstract UUID evalUUID()
157 throws InstallationException;;
158
159 /**
160 * This Method extracts the Revision from the program.
161 *
162 * @return Revision of the program
163 * @throws InstallationException on error
164 */
165 protected abstract String evalRevision()
166 throws InstallationException;;
167
168 /**
169 * Import related source code into the eFaps DataBase. If the source code
170 * does not exists, the source code is created in eFaps.
171 *
172 * @throws InstallationException on error
173 * @see #searchInstance()
174 * @see #createInstance()
175 * @see #updateDB(Instance)
176 */
177 public void execute()
178 throws InstallationException
179 {
180 Instance instance = searchInstance();
181 if (instance == null) {
182 instance = createInstance();
183 }
184 updateDB(instance);
185 }
186
187 /**
188 * Method to search the Instance which is imported.
189 *
190 * @return Instance of the imported program
191 * @throws InstallationException if search failed
192 */
193 public Instance searchInstance()
194 throws InstallationException
195 {
196 Instance instance = null;
197 try {
198 // check if type exists. Necessary for first time installations
199 if (this.ciType.getType() != null) {
200 final QueryBuilder queryBldr = new QueryBuilder(this.ciType);
201 queryBldr.addWhereAttrEqValue(CIAdminProgram.Abstract.Name, this.programName);
202 final InstanceQuery query = queryBldr.getQuery();
203 query.executeWithoutAccessCheck();
204 if (query.next()) {
205 instance = query.getCurrentValue();
206 }
207 }
208 } catch (final EFapsException e) {
209 throw new InstallationException("Could not found '" + this.ciType + "' '" + this.programName + "'", e);
210 }
211
212 return instance;
213 }
214
215 /**
216 * Creates an instance of a source object in eFaps for given name.
217 *
218 * @return new created instance
219 * @throws InstallationException on error
220 * @see #programName
221 */
222 protected Instance createInstance()
223 throws InstallationException
224 {
225 final Insert insert;
226 try {
227 insert = new Insert(this.ciType);
228 insert.add("Name", this.programName);
229 if (getEFapsUUID() != null) {
230 insert.add("UUID", getEFapsUUID().toString());
231 }
232 insert.execute();
233 } catch (final EFapsException e) {
234 throw new InstallationException("Could not create " + this.ciType + " " + getProgramName(), e);
235 }
236 return insert.getInstance();
237 }
238
239 /**
240 * Stores the read source code in eFaps. This is done with a check in.
241 *
242 * @param _instance instance (object id) of the source code object
243 * in eFaps
244 * @throws InstallationException if source code in eFaps could not
245 * updated or the source code could not encoded
246 */
247 public void updateDB(final Instance _instance)
248 throws InstallationException
249 {
250 try {
251 final InputStream is = newCodeInputStream();
252 final Checkin checkin = new Checkin(_instance);
253 checkin.executeWithoutAccessCheck(getProgramName(), is, is.available());
254 } catch (final UnsupportedEncodingException e) {
255 throw new InstallationException("Encoding failed for " + this.programName, e);
256 } catch (final EFapsException e) {
257 throw new InstallationException("Could not check in " + this.programName, e);
258 } catch (final IOException e) {
259 throw new InstallationException("Reading from inoutstream faild for " + this.programName, e);
260 }
261 }
262
263 /**
264 * Creates a new byte array input stream for {@link #code} which is encoded
265 * in character set {@link #ENCODING}.
266 *
267 * @return byte array input stream
268 * @throws UnsupportedEncodingException if {@link #code} could not be
269 * encoded
270 * @see #code
271 */
272 protected InputStream newCodeInputStream()
273 throws UnsupportedEncodingException
274 {
275 return new ByteArrayInputStream(this.code.toString().getBytes(AbstractSourceImporter.ENCODING));
276 }
277
278 /**
279 * Getter method for instance variable {@link #code}.
280 *
281 * @return value for instance variable {@link #code}
282 */
283 public StringBuilder getCode()
284 {
285 return this.code;
286 }
287
288 /**
289 * Getter method for instance variable {@link #url}.
290 *
291 * @return value for instance variable {@link #url}
292 */
293 public URL getUrl()
294 {
295 return this.url;
296 }
297
298 /**
299 * Getter Method for instance variable {@link #eFapsUUID}.
300 *
301 * @return value for instance variable {@link #eFapsUUID}
302 */
303 public UUID getEFapsUUID()
304 {
305 return this.eFapsUUID;
306 }
307
308 /**
309 * Getter Method for instance variable {@link #revision}.
310 *
311 * @return value for instance variable {@link #revision}
312 */
313 public String getRevision()
314 {
315 return this.revision;
316 }
317
318 /**
319 * Getter method for instance variable {@link #programName}.
320 *
321 * @return value of instance variable className
322 * @see #programName
323 */
324 public final String getProgramName()
325 {
326 return this.programName;
327 }
328 }