KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > execute > JarUtil


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.JarUtil
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.execute;
23
24 import org.apache.derby.iapi.reference.Property;
25 import org.apache.derby.iapi.util.IdUtil;
26 import org.apache.derby.impl.sql.execute.JarDDL;
27 import org.apache.derby.iapi.services.property.PropertyUtil;
28 import org.apache.derby.iapi.services.loader.ClassFactory;
29 import org.apache.derby.iapi.services.context.ContextService;
30 import org.apache.derby.iapi.services.sanity.SanityManager;
31 import org.apache.derby.iapi.error.StandardException;
32 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
33 import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
34 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
35 import org.apache.derby.iapi.sql.dictionary.FileInfoDescriptor;
36 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
37
38 import org.apache.derby.iapi.sql.depend.DependencyManager;
39 import org.apache.derby.iapi.reference.SQLState;
40 import org.apache.derby.iapi.store.access.FileResource;
41 import org.apache.derby.catalog.UUID;
42 import org.apache.derby.iapi.services.io.FileUtil;
43 import org.apache.derby.io.StorageFile;
44
45 import java.io.IOException JavaDoc;
46 import java.io.InputStream JavaDoc;
47 import java.sql.CallableStatement JavaDoc;
48 import java.sql.Connection JavaDoc;
49 import java.sql.SQLException JavaDoc;
50
51 public class JarUtil
52 {
53     public static final String JavaDoc ADD_JAR_DDL = "ADD JAR";
54     public static final String JavaDoc DROP_JAR_DDL = "DROP JAR";
55     public static final String JavaDoc REPLACE_JAR_DDL = "REPLACE JAR";
56     public static final String JavaDoc READ_JAR = "READ JAR";
57     //
58
//State passed in by the caller
59
private UUID id; //For add null means create a new id.
60
private String JavaDoc schemaName;
61     private String JavaDoc sqlName;
62
63     //Derived state
64
private LanguageConnectionContext lcc;
65     private FileResource fr;
66     private DataDictionary dd;
67     private DataDescriptorGenerator ddg;
68     
69     //
70
//State derived from the caller's context
71
public JarUtil(UUID id, String JavaDoc schemaName, String JavaDoc sqlName)
72          throws StandardException
73     {
74         this.id = id;
75         this.schemaName = schemaName;
76         this.sqlName = sqlName;
77
78         lcc = (LanguageConnectionContext)
79             ContextService.getContext(LanguageConnectionContext.CONTEXT_ID);
80         fr = lcc.getTransactionExecute().getFileHandler();
81         dd = lcc.getDataDictionary();
82         ddg = dd.getDataDescriptorGenerator();
83     }
84
85     /**
86       Add a jar file to the current connection's database.
87
88       @param id The id for the jar file we add. If null this makes up a new id.
89       @param schemaName the name for the schema that holds the jar file.
90       @param sqlName the sql name for the jar file.
91       @param externalPath the path for the jar file to add.
92       @return The generationId for the jar file we add.
93
94       @exception StandardException Opps
95       */

96     static public long
97     add(UUID id, String JavaDoc schemaName, String JavaDoc sqlName, String JavaDoc externalPath)
98          throws StandardException
99     {
100         JarUtil jutil = new JarUtil(id, schemaName, sqlName);
101         InputStream JavaDoc is = null;
102         
103         try {
104             is = FileUtil.getInputStream(externalPath, 0);
105             return jutil.add(is);
106         } catch (java.io.IOException JavaDoc fnfe) {
107             throw StandardException.newException(SQLState.SQLJ_INVALID_JAR, fnfe, externalPath);
108         }
109         finally {
110             try {if (is != null) is.close();}
111             catch (IOException JavaDoc ioe) {}
112         }
113     }
114
115     /**
116       Add a jar file to the current connection's database.
117
118       <P> The reason for adding the jar file in this private instance
119       method is that it allows us to share set up logic with drop and
120       replace.
121       @param is A stream for reading the content of the file to add.
122       @exception StandardException Opps
123       */

124     public long add(InputStream JavaDoc is) throws StandardException
125     {
126         //
127
//Like create table we say we are writing before we read the dd
128
dd.startWriting(lcc);
129         FileInfoDescriptor fid = getInfo();
130         if (fid != null)
131             throw
132                 StandardException.newException(SQLState.LANG_OBJECT_ALREADY_EXISTS_IN_OBJECT,
133                                                fid.getDescriptorType(), sqlName, fid.getSchemaDescriptor().getDescriptorType(), schemaName);
134
135         try {
136             notifyLoader(false);
137             dd.invalidateAllSPSPlans();
138             long generationId = fr.add(JarDDL.mkExternalName(schemaName, sqlName, fr.getSeparatorChar()),is);
139
140             SchemaDescriptor sd = dd.getSchemaDescriptor(schemaName, null, true);
141
142             fid = ddg.newFileInfoDescriptor(id, sd,
143                             sqlName, generationId);
144             dd.addDescriptor(fid, sd, DataDictionary.SYSFILES_CATALOG_NUM,
145                              false, lcc.getTransactionExecute());
146             return generationId;
147         } finally {
148             notifyLoader(true);
149         }
150     }
151
152     /**
153       Drop a jar file from the current connection's database.
154
155       @param id The id for the jar file we drop. Ignored if null.
156       @param schemaName the name for the schema that holds the jar file.
157       @param sqlName the sql name for the jar file.
158       @param purgeOnCommit True means purge the old jar file on commit. False
159         means leave it around for use by replication.
160
161       @exception StandardException Opps
162       */

163     static public void
164     drop(UUID id, String JavaDoc schemaName, String JavaDoc sqlName,boolean purgeOnCommit)
165          throws StandardException
166     {
167         JarUtil jutil = new JarUtil(id, schemaName,sqlName);
168         jutil.drop(purgeOnCommit);
169     }
170
171     /**
172       Drop a jar file from the current connection's database.
173
174       <P> The reason for dropping the jar file in this private instance
175       method is that it allows us to share set up logic with add and
176       replace.
177       @param purgeOnCommit True means purge the old jar file on commit. False
178         means leave it around for use by replication.
179
180       @exception StandardException Opps
181       */

182     public void drop(boolean purgeOnCommit) throws StandardException
183     {
184         //
185
//Like create table we say we are writing before we read the dd
186
dd.startWriting(lcc);
187         FileInfoDescriptor fid = getInfo();
188         if (fid == null)
189             throw StandardException.newException(SQLState.LANG_FILE_DOES_NOT_EXIST, sqlName,schemaName);
190
191         if (SanityManager.DEBUG)
192         {
193             if (id != null && !fid.getUUID().equals(id))
194             {
195                 SanityManager.THROWASSERT("Drop id mismatch want="+id+
196                         " have "+fid.getUUID());
197             }
198         }
199
200         String JavaDoc dbcp_s = PropertyUtil.getServiceProperty(lcc.getTransactionExecute(),Property.DATABASE_CLASSPATH);
201         if (dbcp_s != null)
202         {
203             String JavaDoc[][]dbcp= IdUtil.parseDbClassPath(dbcp_s,
204                                                             lcc.getIdentifierCasing() != lcc.ANTI_ANSI_CASING );
205             boolean found = false;
206             //
207
//Look for the jar we are dropping on our database classpath.
208
//We don't concern ourselves with 3 part names since they may
209
//refer to a jar file in another database and may not occur in
210
//a database classpath that is stored in the propert congomerate.
211
for (int ix=0;ix<dbcp.length;ix++)
212                 if (dbcp.length == 2 &&
213                     dbcp[ix][0].equals(schemaName) && dbcp[ix][1].equals(sqlName))
214                     found = true;
215             if (found)
216                 throw StandardException.newException(SQLState.LANG_CANT_DROP_JAR_ON_DB_CLASS_PATH_DURING_EXECUTION,
217                                     IdUtil.mkQualifiedName(schemaName,sqlName),
218                                     dbcp_s);
219         }
220
221         try {
222         
223             notifyLoader(false);
224             dd.invalidateAllSPSPlans();
225             DependencyManager dm = dd.getDependencyManager();
226             dm.invalidateFor(fid, DependencyManager.DROP_JAR, lcc);
227
228             dd.dropFileInfoDescriptor(fid);
229
230             fr.remove(JarDDL.mkExternalName(schemaName, sqlName, fr.getSeparatorChar()),
231                 fid.getGenerationId(), true /*purgeOnCommit*/);
232         } finally {
233             notifyLoader(true);
234         }
235     }
236
237     /**
238       Replace a jar file from the current connection's database with the content of an
239       external file.
240
241
242       @param id The id for the jar file we add. Ignored if null.
243       @param schemaName the name for the schema that holds the jar file.
244       @param sqlName the sql name for the jar file.
245       @param externalPath the path for the jar file to add.
246       @param purgeOnCommit True means purge the old jar file on commit. False
247         means leave it around for use by replication.
248       @return The new generationId for the jar file we replace.
249
250       @exception StandardException Opps
251       */

252     static public long
253     replace(UUID id,String JavaDoc schemaName, String JavaDoc sqlName,
254             String JavaDoc externalPath,boolean purgeOnCommit)
255          throws StandardException
256     {
257         JarUtil jutil = new JarUtil(id,schemaName,sqlName);
258         InputStream JavaDoc is = null;
259         
260
261         try {
262             is = FileUtil.getInputStream(externalPath, 0);
263
264             return jutil.replace(is,purgeOnCommit);
265         } catch (java.io.IOException JavaDoc fnfe) {
266             throw StandardException.newException(SQLState.SQLJ_INVALID_JAR, fnfe, externalPath);
267         }
268         finally {
269             try {if (is != null) is.close();}
270             catch (IOException JavaDoc ioe) {}
271         }
272     }
273
274     /**
275       Replace a jar file in the current connection's database with the
276       content of an external file.
277
278       <P> The reason for adding the jar file in this private instance
279       method is that it allows us to share set up logic with add and
280       drop.
281       @param is An input stream for reading the new content of the jar file.
282       @param purgeOnCommit True means purge the old jar file on commit. False
283         means leave it around for use by replication.
284       @exception StandardException Opps
285       */

286     public long replace(InputStream JavaDoc is,boolean purgeOnCommit) throws StandardException
287     {
288         //
289
//Like create table we say we are writing before we read the dd
290
dd.startWriting(lcc);
291
292         //
293
//Temporarily drop the FileInfoDescriptor from the data dictionary.
294
FileInfoDescriptor fid = getInfo();
295         if (fid == null)
296             throw StandardException.newException(SQLState.LANG_FILE_DOES_NOT_EXIST, sqlName,schemaName);
297
298         if (SanityManager.DEBUG)
299         {
300             if (id != null && !fid.getUUID().equals(id))
301             {
302                 SanityManager.THROWASSERT("Replace id mismatch want="+
303                     id+" have "+fid.getUUID());
304             }
305         }
306
307         try {
308             // disable loads from this jar
309
notifyLoader(false);
310             dd.invalidateAllSPSPlans();
311             dd.dropFileInfoDescriptor(fid);
312
313             //
314
//Replace the file.
315
long generationId =
316                 fr.replace(JarDDL.mkExternalName(schemaName, sqlName, fr.getSeparatorChar()),
317                     fid.getGenerationId(), is, purgeOnCommit);
318
319             //
320
//Re-add the descriptor to the data dictionary.
321
FileInfoDescriptor fid2 =
322                 ddg.newFileInfoDescriptor(fid.getUUID(),fid.getSchemaDescriptor(),
323                                 sqlName,generationId);
324             dd.addDescriptor(fid2, fid.getSchemaDescriptor(),
325                              DataDictionary.SYSFILES_CATALOG_NUM, false, lcc.getTransactionExecute());
326             return generationId;
327
328         } finally {
329
330             // reenable class loading from this jar
331
notifyLoader(true);
332         }
333     }
334
335     /**
336       Get the FileInfoDescriptor for a jar file from the current connection's database or
337       null if it does not exist.
338
339       @param schemaName the name for the schema that holds the jar file.
340       @param sqlName the sql name for the jar file.
341       @return The FileInfoDescriptor.
342       @exception StandardException Opps
343       */

344     public static FileInfoDescriptor getInfo(String JavaDoc schemaName, String JavaDoc sqlName, String JavaDoc statementType)
345          throws StandardException
346     {
347         JarUtil jUtil = new JarUtil(null,schemaName,sqlName);
348         return jUtil.getInfo();
349     }
350
351     /**
352       Get the FileInfoDescriptor for the Jar file or null if it does not exist.
353       @exception StandardException Ooops
354       */

355     private FileInfoDescriptor getInfo()
356          throws StandardException
357     {
358         SchemaDescriptor sd = dd.getSchemaDescriptor(schemaName, null, true);
359         return dd.getFileInfoDescriptor(sd,sqlName);
360     }
361
362     // get the current version of the jar file as a File or InputStream
363
public static Object JavaDoc getAsObject(String JavaDoc schemaName, String JavaDoc sqlName)
364          throws StandardException
365     {
366         JarUtil jUtil = new JarUtil(null,schemaName,sqlName);
367
368         FileInfoDescriptor fid = jUtil.getInfo();
369         if (fid == null)
370             throw StandardException.newException(SQLState.LANG_FILE_DOES_NOT_EXIST, sqlName,schemaName);
371
372         long generationId = fid.getGenerationId();
373
374         StorageFile f = jUtil.getAsFile(generationId);
375         if (f != null)
376             return f;
377
378         return jUtil.getAsStream(generationId);
379     }
380
381     private StorageFile getAsFile(long generationId) {
382         return fr.getAsFile(JarDDL.mkExternalName(schemaName, sqlName, fr.getSeparatorChar()), generationId);
383     }
384
385     public static InputStream JavaDoc getAsStream(String JavaDoc schemaName, String JavaDoc sqlName,
386         long generationId) throws StandardException {
387         JarUtil jUtil = new JarUtil(null,schemaName,sqlName);
388
389         return jUtil.getAsStream(generationId);
390     }
391
392     private InputStream JavaDoc getAsStream(long generationId) throws StandardException {
393         try {
394             return fr.getAsStream(JarDDL.mkExternalName(schemaName, sqlName, fr.getSeparatorChar()), generationId);
395         } catch (IOException JavaDoc ioe) {
396             throw StandardException.newException(SQLState.LANG_FILE_ERROR, ioe, ioe.toString());
397         }
398     }
399
400     private void notifyLoader(boolean reload) throws StandardException {
401         ClassFactory cf = lcc.getLanguageConnectionFactory().getClassFactory();
402         cf.notifyModifyJar(reload);
403     }
404 }
405
Popular Tags