00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 package org.openmobileis.oscar.utils;
00037
00038 import java.io.*;
00039 import java.security.AccessController;
00040 import java.security.PrivilegedActionException;
00041 import java.security.PrivilegedExceptionAction;
00042 import java.util.HashMap;
00043 import java.util.Iterator;
00044 import java.util.Map;
00045 import java.util.jar.JarFile;
00046 import java.util.jar.Manifest;
00047 import java.util.zip.ZipEntry;
00048
00049 import org.osgi.framework.Bundle;
00050 import org.osgi.framework.BundleActivator;
00051 import org.osgi.service.log.LogService;
00052 import org.ungoverned.oscar.cache.BundleArchive;
00053 import org.ungoverned.oscar.util.*;
00054
00062 public class OpenmisOscarBundleArchive implements BundleArchive
00063 {
00064 private static final transient String BUNDLE_JAR_FILE = "bundle.jar";
00065 private static final transient String BUNDLE_LOCATION_FILE = "bundle.location";
00066 private static final transient String BUNDLE_STATE_FILE = "bundle.state";
00067 private static final transient String BUNDLE_START_LEVEL_FILE = "bundle.startlevel";
00068 private static final transient String REFRESH_COUNTER_FILE = "refresh.counter";
00069 private static final transient String BUNDLE_ACTIVATOR_FILE = "bundle.activator";
00070
00071 private static final transient String REVISION_DIRECTORY = "version";
00072 private static final transient String EMBEDDED_DIRECTORY = "embedded";
00073 private static final transient String LIBRARY_DIRECTORY = "lib";
00074 private static final transient String DATA_DIRECTORY = "data";
00075
00076 private static final transient String ACTIVE_STATE = "active";
00077 private static final transient String INSTALLED_STATE = "installed";
00078 private static final transient String UNINSTALLED_STATE = "uninstalled";
00079
00080 private LogService m_logger = null;
00081 private long m_id = -1;
00082 private File m_dir = null;
00083 private String m_location = null;
00084 private int m_persistentState = -1;
00085 private int m_startLevel = -1;
00086 private Map m_currentHeader = null;
00087
00088 private long m_refreshCount = -1;
00089 private int m_revisionCount = -1;
00090
00091 public OpenmisOscarBundleArchive(LogService logger, File dir, long id, String location, InputStream is)
00092 throws Exception
00093 {
00094 this(logger, dir, id);
00095 m_location = location;
00096
00097
00098 try
00099 {
00100 initialize(is);
00101 }
00102 catch (Exception ex)
00103 {
00104 if (!deleteDirectoryTree(dir))
00105 {
00106 m_logger.log(
00107 LogService.LOG_ERROR,
00108 "Unable to delete the archive directory: " + id);
00109 }
00110 throw ex;
00111 }
00112 }
00113
00114 public OpenmisOscarBundleArchive(LogService logger, File dir, long id)
00115 {
00116 m_logger = logger;
00117 m_dir = dir;
00118 m_id = id;
00119 if (m_id <= 0)
00120 {
00121 throw new IllegalArgumentException(
00122 "Bundle ID cannot be less than or equal to zero.");
00123 }
00124 }
00125
00126 private void initialize(InputStream is)
00127 throws Exception
00128 {
00129 if (System.getSecurityManager() != null)
00130 {
00131 try
00132 {
00133 AccessController.doPrivileged(
00134 new PrivilegedAction(
00135 PrivilegedAction.INITIALIZE_ACTION, this, is));
00136 }
00137 catch (PrivilegedActionException ex)
00138 {
00139 throw ((PrivilegedActionException) ex).getException();
00140 }
00141 }
00142 else
00143 {
00144 initializeUnchecked(is);
00145 }
00146 }
00147
00148 private void initializeUnchecked(InputStream is)
00149 throws Exception
00150 {
00151 FileWriter fw = null;
00152 BufferedWriter bw = null;
00153
00154 try
00155 {
00156
00157 if (!m_dir.mkdir())
00158 {
00159 m_logger.log(
00160 LogService.LOG_ERROR,
00161 "DefaultBundleArchive: Unable to create archive directory.");
00162 throw new IOException("Unable to create archive directory.");
00163 }
00164
00165
00166 File file = new File(m_dir, BUNDLE_LOCATION_FILE);
00167 fw = new FileWriter(file);
00168 bw = new BufferedWriter(fw);
00169 bw.write(m_location, 0, m_location.length());
00170
00171
00172
00173
00174
00175 File revisionDir = new File(m_dir, REVISION_DIRECTORY + "0.0");
00176 if (!revisionDir.mkdir())
00177 {
00178 m_logger.log(
00179 LogService.LOG_ERROR,
00180 "DefaultBundleArchive: Unable to create revision directory.");
00181 throw new IOException("Unable to create revision directory.");
00182 }
00183
00184
00185 file = new File(revisionDir, BUNDLE_JAR_FILE);
00186 copy(is, file);
00187
00188
00189 preprocessBundleJar(0, revisionDir);
00190
00191 }
00192 finally
00193 {
00194 if (is != null) is.close();
00195 if (bw != null) bw.close();
00196 if (fw != null) fw.close();
00197 }
00198 }
00199
00200 public File getDirectory()
00201 {
00202 return m_dir;
00203 }
00204
00205 public long getId()
00206 {
00207 return m_id;
00208 }
00209
00210 public String getLocation()
00211 throws Exception
00212 {
00213 if (m_location != null)
00214 {
00215 return m_location;
00216 }
00217 else if (System.getSecurityManager() != null)
00218 {
00219 try
00220 {
00221 return (String) AccessController.doPrivileged(
00222 new PrivilegedAction(
00223 PrivilegedAction.GET_LOCATION_ACTION, this));
00224 }
00225 catch (PrivilegedActionException ex)
00226 {
00227 throw ((PrivilegedActionException) ex).getException();
00228 }
00229 }
00230 else
00231 {
00232 return getLocationUnchecked();
00233 }
00234 }
00235
00236 private String getLocationUnchecked()
00237 throws Exception
00238 {
00239
00240 File locFile = new File(m_dir, BUNDLE_LOCATION_FILE);
00241
00242
00243 FileReader fr = null;
00244 BufferedReader br = null;
00245 try
00246 {
00247 fr = new FileReader(locFile);
00248 br = new BufferedReader(fr);
00249 m_location = br.readLine();
00250 return m_location;
00251 }
00252 finally
00253 {
00254 if (br != null) br.close();
00255 if (fr != null) fr.close();
00256 }
00257 }
00258
00259 public int getPersistentState()
00260 throws Exception
00261 {
00262 if (m_persistentState >= 0)
00263 {
00264 return m_persistentState;
00265 }
00266 else if (System.getSecurityManager() != null)
00267 {
00268 try
00269 {
00270 return ((Integer) AccessController.doPrivileged(
00271 new PrivilegedAction(
00272 PrivilegedAction.GET_PERSISTENT_STATE_ACTION, this))).intValue();
00273 }
00274 catch (PrivilegedActionException ex)
00275 {
00276 throw ((PrivilegedActionException) ex).getException();
00277 }
00278 }
00279 else
00280 {
00281 return getPersistentStateUnchecked();
00282 }
00283 }
00284
00285 private int getPersistentStateUnchecked()
00286 throws Exception
00287 {
00288
00289 File stateFile = new File(m_dir, BUNDLE_STATE_FILE);
00290
00291
00292
00293 if (!stateFile.exists())
00294 {
00295 return Bundle.INSTALLED;
00296 }
00297
00298
00299 FileReader fr = null;
00300 BufferedReader br= null;
00301 try
00302 {
00303 fr = new FileReader(stateFile);
00304 br = new BufferedReader(fr);
00305 String s = br.readLine();
00306 if (s.equals(ACTIVE_STATE))
00307 {
00308 m_persistentState = Bundle.ACTIVE;
00309 }
00310 else if (s.equals(UNINSTALLED_STATE))
00311 {
00312 m_persistentState = Bundle.UNINSTALLED;
00313 }
00314 else
00315 {
00316 m_persistentState = Bundle.INSTALLED;
00317 }
00318 return m_persistentState;
00319 }
00320 finally
00321 {
00322 if (br != null) br.close();
00323 if (fr != null) fr.close();
00324 }
00325 }
00326
00327 public void setPersistentState(int state)
00328 throws Exception
00329 {
00330 if (System.getSecurityManager() != null)
00331 {
00332 try
00333 {
00334 AccessController.doPrivileged(
00335 new PrivilegedAction(
00336 PrivilegedAction.SET_PERSISTENT_STATE_ACTION, this, state));
00337 }
00338 catch (PrivilegedActionException ex)
00339 {
00340 throw ((PrivilegedActionException) ex).getException();
00341 }
00342 }
00343 else
00344 {
00345 setPersistentStateUnchecked(state);
00346 }
00347 }
00348
00349 private void setPersistentStateUnchecked(int state)
00350 throws Exception
00351 {
00352
00353 File stateFile = new File(m_dir, BUNDLE_STATE_FILE);
00354
00355
00356 FileWriter fw = null;
00357 BufferedWriter bw= null;
00358 try
00359 {
00360 fw = new FileWriter(stateFile);
00361 bw = new BufferedWriter(fw);
00362 String s = null;
00363 switch (state)
00364 {
00365 case Bundle.ACTIVE:
00366 s = ACTIVE_STATE;
00367 break;
00368 case Bundle.UNINSTALLED:
00369 s = UNINSTALLED_STATE;
00370 break;
00371 default:
00372 s = INSTALLED_STATE;
00373 break;
00374 }
00375 bw.write(s, 0, s.length());
00376 m_persistentState = state;
00377 }
00378 catch (IOException ex)
00379 {
00380 m_logger.log(
00381 LogService.LOG_ERROR,
00382 "DefaultBundleArchive: Unable to record state: " + ex);
00383 throw ex;
00384 }
00385 finally
00386 {
00387 if (bw != null) bw.close();
00388 if (fw != null) fw.close();
00389 }
00390 }
00391
00392 public int getStartLevel()
00393 throws Exception
00394 {
00395 if (m_startLevel >= 0)
00396 {
00397 return m_startLevel;
00398 }
00399 else if (System.getSecurityManager() != null)
00400 {
00401 try
00402 {
00403 return ((Integer) AccessController.doPrivileged(
00404 new PrivilegedAction(
00405 PrivilegedAction.GET_START_LEVEL_ACTION, this))).intValue();
00406 }
00407 catch (PrivilegedActionException ex)
00408 {
00409 throw ((PrivilegedActionException) ex).getException();
00410 }
00411 }
00412 else
00413 {
00414 return getStartLevelUnchecked();
00415 }
00416 }
00417
00418 private int getStartLevelUnchecked()
00419 throws Exception
00420 {
00421
00422 File levelFile = new File(m_dir, BUNDLE_START_LEVEL_FILE);
00423
00424
00425
00426 if (!levelFile.exists())
00427 {
00428 return -1;
00429 }
00430
00431
00432 FileReader fr = null;
00433 BufferedReader br= null;
00434 try
00435 {
00436 fr = new FileReader(levelFile);
00437 br = new BufferedReader(fr);
00438 m_startLevel = Integer.parseInt(br.readLine());
00439 return m_startLevel;
00440 }
00441 finally
00442 {
00443 if (br != null) br.close();
00444 if (fr != null) fr.close();
00445 }
00446 }
00447
00448 public void setStartLevel(int level)
00449 throws Exception
00450 {
00451 if (System.getSecurityManager() != null)
00452 {
00453 try
00454 {
00455 AccessController.doPrivileged(
00456 new PrivilegedAction(
00457 PrivilegedAction.SET_START_LEVEL_ACTION, this, level));
00458 }
00459 catch (PrivilegedActionException ex)
00460 {
00461 throw ((PrivilegedActionException) ex).getException();
00462 }
00463 }
00464 else
00465 {
00466 setStartLevelUnchecked(level);
00467 }
00468 }
00469
00470 private void setStartLevelUnchecked(int level)
00471 throws Exception
00472 {
00473
00474 File levelFile = new File(m_dir, BUNDLE_START_LEVEL_FILE);
00475
00476
00477 FileWriter fw = null;
00478 BufferedWriter bw = null;
00479 try
00480 {
00481 fw = new FileWriter(levelFile);
00482 bw = new BufferedWriter(fw);
00483 String s = Integer.toString(level);
00484 bw.write(s, 0, s.length());
00485 m_startLevel = level;
00486 }
00487 catch (IOException ex)
00488 {
00489 m_logger.log(
00490 LogService.LOG_ERROR,
00491 "DefaultBundleArchive: Unable to record start leel: " + ex);
00492 throw ex;
00493 }
00494 finally
00495 {
00496 if (bw != null) bw.close();
00497 if (fw != null) fw.close();
00498 }
00499 }
00500
00501 public File getDataFile(String fileName)
00502 throws Exception
00503 {
00504
00505 if ((fileName.length() > 0) && (fileName.charAt(0) == File.separatorChar))
00506 throw new IllegalArgumentException("The data file path must be relative, not absolute.");
00507 else if (fileName.indexOf("..") >= 0)
00508 throw new IllegalArgumentException("The data file path cannot contain a reference to the \"..\" directory.");
00509
00510
00511 File dataDir = new File(m_dir, DATA_DIRECTORY);
00512
00513 if (System.getSecurityManager() != null)
00514 {
00515 try
00516 {
00517 AccessController.doPrivileged(
00518 new PrivilegedAction(
00519 PrivilegedAction.CREATE_DATA_DIR_ACTION, this, dataDir));
00520 }
00521 catch (PrivilegedActionException ex)
00522 {
00523 throw ((PrivilegedActionException) ex).getException();
00524 }
00525 }
00526 else
00527 {
00528 createDataDirectoryUnchecked(dataDir);
00529 }
00530
00531
00532 return new File(dataDir, fileName);
00533 }
00534
00535 private void createDataDirectoryUnchecked(File dir)
00536 throws Exception
00537 {
00538
00539 if (!dir.exists())
00540 {
00541 if (!dir.mkdir())
00542 {
00543 throw new IOException("Unable to create bundle data directory.");
00544 }
00545 }
00546 }
00547
00548 public BundleActivator getActivator(ClassLoader loader)
00549 throws Exception
00550 {
00551 if (System.getSecurityManager() != null)
00552 {
00553 try
00554 {
00555 return (BundleActivator) AccessController.doPrivileged(
00556 new PrivilegedAction(
00557 PrivilegedAction.GET_ACTIVATOR_ACTION, this, loader));
00558 }
00559 catch (PrivilegedActionException ex)
00560 {
00561 throw ((PrivilegedActionException) ex).getException();
00562 }
00563 }
00564 else
00565 {
00566 return getActivatorUnchecked(loader);
00567 }
00568 }
00569
00570 private BundleActivator getActivatorUnchecked(ClassLoader loader)
00571 throws Exception
00572 {
00573
00574 File activatorFile = new File(m_dir, BUNDLE_ACTIVATOR_FILE);
00575
00576
00577 if (!activatorFile.exists())
00578 return null;
00579
00580
00581 InputStream is = null;
00582 ObjectInputStreamX ois = null;
00583 try
00584 {
00585 is = new FileInputStream(activatorFile);
00586 ois = new ObjectInputStreamX(is, loader);
00587 Object o = ois.readObject();
00588 return (BundleActivator) o;
00589 }
00590 catch (Exception ex)
00591 {
00592 m_logger.log(
00593 LogService.LOG_ERROR,
00594 "DefaultBundleArchive: Trying to deserialize - " + ex);
00595 }
00596 finally
00597 {
00598 if (ois != null) ois.close();
00599 if (is != null) is.close();
00600 }
00601
00602 return null;
00603 }
00604
00605 public void setActivator(Object obj)
00606 throws Exception
00607 {
00608 if (System.getSecurityManager() != null)
00609 {
00610 try
00611 {
00612 AccessController.doPrivileged(
00613 new PrivilegedAction(
00614 PrivilegedAction.SET_ACTIVATOR_ACTION, this, obj));
00615 }
00616 catch (PrivilegedActionException ex)
00617 {
00618 throw ((PrivilegedActionException) ex).getException();
00619 }
00620 }
00621 else
00622 {
00623 setActivatorUnchecked(obj);
00624 }
00625 }
00626
00627 private void setActivatorUnchecked(Object obj)
00628 throws Exception
00629 {
00630 if (!(obj instanceof Serializable))
00631 {
00632 return;
00633 }
00634
00635
00636 File activatorFile = new File(m_dir, BUNDLE_ACTIVATOR_FILE);
00637
00638
00639 OutputStream os = null;
00640 ObjectOutputStream oos = null;
00641 try
00642 {
00643 os = new FileOutputStream(activatorFile);
00644 oos = new ObjectOutputStream(os);
00645 oos.writeObject(obj);
00646 }
00647 catch (IOException ex)
00648 {
00649 m_logger.log(
00650 LogService.LOG_ERROR,
00651 "DefaultBundleArchive: Unable to serialize activator - " + ex);
00652 throw ex;
00653 }
00654 finally
00655 {
00656 if (oos != null) oos.close();
00657 if (os != null) os.close();
00658 }
00659 }
00660
00661 public int getRevisionCount()
00662 throws Exception
00663 {
00664 if (System.getSecurityManager() != null)
00665 {
00666 try
00667 {
00668 return ((Integer) AccessController.doPrivileged(
00669 new PrivilegedAction(
00670 PrivilegedAction.GET_REVISION_COUNT_ACTION, this))).intValue();
00671 }
00672 catch (PrivilegedActionException ex)
00673 {
00674 throw ((PrivilegedActionException) ex).getException();
00675 }
00676 }
00677 else
00678 {
00679 return getRevisionCountUnchecked();
00680 }
00681 }
00682
00683 public int getRevisionCountUnchecked()
00684 {
00685
00686
00687
00688 if (m_revisionCount <= 0)
00689 {
00690 m_revisionCount = 0;
00691 File[] children = m_dir.listFiles();
00692 for (int i = 0; (children != null) && (i < children.length); i++)
00693 {
00694 if (children[i].getName().startsWith(REVISION_DIRECTORY))
00695 {
00696 m_revisionCount++;
00697 }
00698 }
00699 }
00700 return m_revisionCount;
00701 }
00702
00703 public Map getManifestHeader(int revision)
00704 throws Exception
00705 {
00706
00707
00708 if ((revision == (getRevisionCount() - 1)) && (m_currentHeader != null))
00709 {
00710 return m_currentHeader;
00711 }
00712
00713
00714 File revisionDir = new File(
00715 m_dir, REVISION_DIRECTORY + getRefreshCount() + "." + revision);
00716
00717
00718 JarFile jarFile = null;
00719
00720 try
00721 {
00722
00723 if (System.getSecurityManager() != null)
00724 {
00725 jarFile = (JarFile) AccessController.doPrivileged(
00726 new PrivilegedAction(
00727 PrivilegedAction.OPEN_BUNDLE_JAR_ACTION, this, revisionDir));
00728 }
00729 else
00730 {
00731 jarFile = openBundleJarUnchecked(revisionDir);
00732 }
00733
00734
00735 if (jarFile == null)
00736 {
00737 throw new IOException("No JAR file found.");
00738 }
00739
00740
00741 Manifest mf = jarFile.getManifest();
00742
00743 Map map = new CaseInsensitiveMap(mf.getMainAttributes());
00744
00745
00746 if (revision == (getRevisionCount() - 1))
00747 {
00748 m_currentHeader = map;
00749 }
00750 return map;
00751
00752 } catch (PrivilegedActionException ex) {
00753 throw ((PrivilegedActionException) ex).getException();
00754 } finally {
00755 if (jarFile != null) jarFile.close();
00756 }
00757 }
00758
00759 private JarFile openBundleJarUnchecked(File revisionDir)
00760 throws Exception
00761 {
00762
00763 File bundleJar = new File(revisionDir, BUNDLE_JAR_FILE);
00764
00765 return new JarFile(bundleJar);
00766 }
00767
00768 public String[] getClassPath(int revision)
00769 throws Exception
00770 {
00771 if (System.getSecurityManager() != null)
00772 {
00773 try
00774 {
00775 return (String []) AccessController.doPrivileged(
00776 new PrivilegedAction(
00777 PrivilegedAction.GET_CLASS_PATH_ACTION, this, revision));
00778 }
00779 catch (PrivilegedActionException ex)
00780 {
00781 throw ((PrivilegedActionException) ex).getException();
00782 }
00783 }
00784 else
00785 {
00786 return getClassPathUnchecked(revision);
00787 }
00788 }
00789
00790 private String[] getClassPathUnchecked(int revision)
00791 throws Exception
00792 {
00793
00794 File revisionDir = new File(
00795 m_dir, REVISION_DIRECTORY + getRefreshCount() + "." + revision);
00796
00797
00798 Map map = getManifestHeader(revision);
00799 if (map == null)
00800 {
00801 map = new HashMap();
00802 }
00803
00804
00805 String classPath = null;
00806 Iterator iter = map.entrySet().iterator();
00807 while ((classPath == null) && iter.hasNext())
00808 {
00809 Map.Entry entry = (Map.Entry) iter.next();
00810 if (entry.getKey().toString().toLowerCase().equals(
00811 OscarConstants.BUNDLE_CLASSPATH.toLowerCase()))
00812 {
00813 classPath = entry.getValue().toString();
00814 }
00815 }
00816
00817
00818 String[] classPathStrings = Util.parseDelimitedString(
00819 classPath, OscarConstants.CLASS_PATH_SEPARATOR);
00820
00821 if (classPathStrings == null)
00822 {
00823 classPathStrings = new String[0];
00824 }
00825
00826
00827 boolean includeDot = false;
00828 for (int i = 0; !includeDot && (i < classPathStrings.length); i++)
00829 {
00830 if (classPathStrings[i].equals(OscarConstants.CLASS_PATH_DOT))
00831 {
00832 includeDot = true;
00833 }
00834 }
00835
00836
00837
00838 File embedDir = new File(revisionDir, EMBEDDED_DIRECTORY);
00839 String[] paths = null;
00840 if (embedDir.exists())
00841 {
00842
00843
00844
00845
00846
00847 File[] children = embedDir.listFiles();
00848 int size = (children == null) ? 0 : children.length;
00849 size = (includeDot) ? size + 1 : size;
00850 paths = new String[size];
00851 for (int i = 0; i < children.length; i++)
00852 {
00853
00854
00855 paths[(includeDot) ? i + 1 : i] = children[i].getPath();
00856 }
00857 }
00858
00859
00860
00861 if ((paths == null) || (paths.length == 0))
00862 {
00863 includeDot = true;
00864 paths = new String[1];
00865 }
00866
00867
00868 if (includeDot)
00869 {
00870 paths[0] = revisionDir + File.separator + BUNDLE_JAR_FILE;
00871 }
00872
00873 return paths;
00874 }
00875
00876
00877 public String findLibrary(int revision, String libName)
00878 throws Exception
00879 {
00880 return findLibraryUnchecked(revision, libName);
00881 }
00882
00883 private String findLibraryUnchecked(int revision, String libName)
00884 throws Exception
00885 {
00886
00887 File revisionDir = new File(
00888 m_dir.getAbsoluteFile(),
00889 REVISION_DIRECTORY + getRefreshCount() + "." + revision);
00890
00891
00892 File libDir = new File(revisionDir, LIBRARY_DIRECTORY);
00893
00894 File libFile = new File(libDir, File.separatorChar + libName);
00895
00896
00897 libDir = libFile.getParentFile();
00898 if (!libDir.exists())
00899 {
00900 if (!libDir.mkdirs())
00901 {
00902 throw new IOException("Unable to create library directory.");
00903 }
00904 }
00905
00906
00907 if (!libFile.exists())
00908 {
00909 JarFile jarFile = null;
00910 InputStream is = null;
00911
00912 try
00913 {
00914 jarFile = openBundleJarUnchecked(revisionDir);
00915 ZipEntry ze = jarFile.getEntry(libName);
00916 if (ze == null)
00917 {
00918 throw new IOException("No JAR entry: " + libName);
00919 }
00920 is = new BufferedInputStream(
00921 jarFile.getInputStream(ze), OpenmisOscarBundleCache.BUFSIZE);
00922 if (is == null)
00923 {
00924 throw new IOException("No input stream: " + libName);
00925 }
00926
00927
00928 copy(is, libFile);
00929
00930 }
00931 finally
00932 {
00933 if (jarFile != null) jarFile.close();
00934 if (is != null) is.close();
00935 }
00936 }
00937
00938 return libFile.toString();
00939 }
00940
00955 private long getRefreshCount()
00956 throws Exception
00957 {
00958
00959
00960 if (m_refreshCount >= 0)
00961 {
00962 return m_refreshCount;
00963 }
00964
00965
00966 File counterFile = new File(m_dir, REFRESH_COUNTER_FILE);
00967
00968
00969
00970 if (!counterFile.exists())
00971 {
00972 return 0;
00973 }
00974
00975
00976 FileReader fr = null;
00977 BufferedReader br = null;
00978 try
00979 {
00980 fr = new FileReader(counterFile);
00981 br = new BufferedReader(fr);
00982 long counter = Long.parseLong(br.readLine());
00983 return counter;
00984 }
00985 finally
00986 {
00987 if (br != null) br.close();
00988 if (fr != null) fr.close();
00989 }
00990 }
00991
01006 private void setRefreshCount(long counter)
01007 throws Exception
01008 {
01009
01010 File counterFile = new File(m_dir, REFRESH_COUNTER_FILE);
01011
01012
01013 FileWriter fw = null;
01014 BufferedWriter bw = null;
01015 try
01016 {
01017 fw = new FileWriter(counterFile);
01018 bw = new BufferedWriter(fw);
01019 String s = Long.toString(counter);
01020 bw.write(s, 0, s.length());
01021 m_refreshCount = counter;
01022 }
01023 catch (IOException ex)
01024 {
01025 m_logger.log(
01026 LogService.LOG_ERROR,
01027 "DefaultBundleArchive: Unable to write counter: " + ex);
01028 throw ex;
01029 }
01030 finally
01031 {
01032 if (bw != null) bw.close();
01033 if (fw != null) fw.close();
01034 }
01035 }
01036
01037
01038
01039
01040
01041 protected static boolean deleteDirectoryTree(File target)
01042 {
01043 if (!target.exists())
01044 {
01045 return true;
01046 }
01047
01048 if (target.isDirectory())
01049 {
01050 File[] files = target.listFiles();
01051 for (int i = 0; i < files.length; i++)
01052 {
01053 deleteDirectoryTree(files[i]);
01054 }
01055 }
01056
01057 return target.delete();
01058 }
01059
01068 private void copy(InputStream is, File outputFile)
01069 throws IOException
01070 {
01071 OutputStream os = null;
01072
01073 try
01074 {
01075 os = new BufferedOutputStream(
01076 new FileOutputStream(outputFile), OpenmisOscarBundleCache.BUFSIZE);
01077 byte[] b = new byte[OpenmisOscarBundleCache.BUFSIZE];
01078 int len = 0;
01079 while ((len = is.read(b)) != -1)
01080 os.write(b, 0, len);
01081 }
01082 finally
01083 {
01084 if (is != null) is.close();
01085 if (os != null) os.close();
01086 }
01087 }
01088
01095 private void preprocessBundleJar(int revision, File revisionDir)
01096 throws Exception
01097 {
01098
01099
01100
01101
01102
01103 File embedDir = new File(revisionDir, EMBEDDED_DIRECTORY);
01104 if (!embedDir.exists())
01105 {
01106 if (!embedDir.mkdir())
01107 {
01108 throw new IOException("Could not create embedded JAR directory.");
01109 }
01110 }
01111
01112 File libDir = new File(revisionDir, LIBRARY_DIRECTORY);
01113 if (!libDir.exists())
01114 {
01115 if (!libDir.mkdir())
01116 {
01117 throw new IOException("Unable to create native library directory.");
01118 }
01119 }
01120
01121
01122
01123
01124
01125 try
01126 {
01127
01128 Map map = getManifestHeader(revision);
01129 if (map == null)
01130 {
01131 map = new HashMap();
01132 }
01133
01134
01135 String classPath = null;
01136 Iterator iter = map.entrySet().iterator();
01137 while ((classPath == null) && iter.hasNext())
01138 {
01139 Map.Entry entry = (Map.Entry) iter.next();
01140 if (entry.getKey().toString().toLowerCase().equals(
01141 OscarConstants.BUNDLE_CLASSPATH.toLowerCase()))
01142 {
01143 classPath = entry.getValue().toString();
01144 }
01145 }
01146
01147
01148 String[] classPathStrings = Util.parseDelimitedString(
01149 classPath, OscarConstants.CLASS_PATH_SEPARATOR);
01150
01151 if (classPathStrings == null)
01152 {
01153 classPathStrings = new String[0];
01154 }
01155
01156 for (int i = 0; i < classPathStrings.length; i++)
01157 {
01158 if (!classPathStrings[i].equals(OscarConstants.CLASS_PATH_DOT))
01159 {
01160 extractEmbeddedJar(revisionDir, classPathStrings[i]);
01161 }
01162 }
01163
01164 }
01165 catch (PrivilegedActionException ex)
01166 {
01167 throw ((PrivilegedActionException) ex).getException();
01168 }
01169 }
01170
01180 private void extractEmbeddedJar(File revisionDir, String jarPath)
01181 throws Exception
01182 {
01183
01184 jarPath = (jarPath.charAt(0) == '/') ? jarPath.substring(1) : jarPath;
01185
01186 String jarName = (jarPath.lastIndexOf('/') >= 0)
01187 ? jarPath.substring(jarPath.lastIndexOf('/') + 1) : jarPath;
01188
01189
01190
01191 File embedFile = new File(
01192 revisionDir, EMBEDDED_DIRECTORY + File.separatorChar + jarName);
01193 if (!embedFile.exists())
01194 {
01195 JarFile jarFile = null;
01196 InputStream is = null;
01197
01198 try
01199 {
01200 jarFile = openBundleJarUnchecked(revisionDir);
01201 ZipEntry ze = jarFile.getEntry(jarPath);
01202 if (ze == null)
01203 {
01204 throw new IOException("No JAR entry: " + jarPath);
01205 }
01206 is = new BufferedInputStream(jarFile.getInputStream(ze), OpenmisOscarBundleCache.BUFSIZE);
01207 if (is == null)
01208 {
01209 throw new IOException("No input stream: " + jarPath);
01210 }
01211
01212
01213 copy(is, embedFile);
01214
01215 }
01216 finally
01217 {
01218 if (jarFile != null) jarFile.close();
01219 if (is != null) is.close();
01220 }
01221 }
01222 }
01223
01224
01225 protected void update(InputStream is) throws Exception
01226 {
01227 if (System.getSecurityManager() != null)
01228 {
01229 try
01230 {
01231 AccessController.doPrivileged(
01232 new PrivilegedAction(
01233 PrivilegedAction.UPDATE_ACTION, this, is));
01234 }
01235 catch (PrivilegedActionException ex)
01236 {
01237 throw ((PrivilegedActionException) ex).getException();
01238 }
01239 }
01240 else
01241 {
01242 updateUnchecked(is);
01243 }
01244 }
01245
01246
01247 private void updateUnchecked(InputStream is) throws Exception
01248 {
01249 File revisionDir = null;
01250
01251 try
01252 {
01253
01254 int revision = getRevisionCountUnchecked();
01255 revisionDir = new File(
01256 m_dir, REVISION_DIRECTORY
01257 + getRefreshCount() + "." + revision);
01258 if (!revisionDir.mkdir())
01259 {
01260 throw new IOException("Unable to create revision directory.");
01261 }
01262
01263
01264 File file = new File(revisionDir, BUNDLE_JAR_FILE);
01265 copy(is, file);
01266
01267 preprocessBundleJar(revision, revisionDir);
01268 }
01269 catch (Exception ex)
01270 {
01271 if ((revisionDir != null) && revisionDir.exists())
01272 {
01273 try
01274 {
01275 deleteDirectoryTree(revisionDir);
01276 }
01277 catch (Exception ex2)
01278 {
01279
01280 m_logger.log(
01281 LogService.LOG_ERROR,
01282 "Unable to remove partial revision directory.", ex2);
01283 }
01284 }
01285 throw ex;
01286 }
01287
01288
01289
01290 m_revisionCount++;
01291
01292
01293 m_currentHeader = null;
01294 }
01295
01296
01297 protected void purge() throws Exception
01298 {
01299 if (System.getSecurityManager() != null)
01300 {
01301 try
01302 {
01303 AccessController.doPrivileged(
01304 new PrivilegedAction(
01305 PrivilegedAction.PURGE_ACTION, this));
01306 }
01307 catch (PrivilegedActionException ex)
01308 {
01309 throw ((PrivilegedActionException) ex).getException();
01310 }
01311 }
01312 else
01313 {
01314 purgeUnchecked();
01315 }
01316 }
01317
01318
01319 private void purgeUnchecked() throws Exception
01320 {
01321
01322 long update = getRefreshCount();
01323
01324 int count = getRevisionCountUnchecked();
01325
01326 File revisionDir = null;
01327 for (int i = 0; i < count - 1; i++)
01328 {
01329 revisionDir = new File(m_dir, REVISION_DIRECTORY + update + "." + i);
01330 if (revisionDir.exists())
01331 {
01332 deleteDirectoryTree(revisionDir);
01333 }
01334 }
01335
01336 setRefreshCount(update + 1);
01337
01338
01339 File currentDir = new File(m_dir, REVISION_DIRECTORY + (update + 1) + ".0");
01340 revisionDir = new File(m_dir, REVISION_DIRECTORY + update + "." + (count - 1));
01341 revisionDir.renameTo(currentDir);
01342
01343
01344
01345 m_revisionCount = 1;
01346
01347
01348 m_currentHeader = null;
01349 }
01350
01351 protected void remove() throws Exception
01352 {
01353 if (System.getSecurityManager() != null)
01354 {
01355 try
01356 {
01357 AccessController.doPrivileged(
01358 new PrivilegedAction(
01359 PrivilegedAction.REMOVE_ACTION, this));
01360 }
01361 catch (PrivilegedActionException ex)
01362 {
01363 throw ((PrivilegedActionException) ex).getException();
01364 }
01365 }
01366 else
01367 {
01368 removeUnchecked();
01369 }
01370 }
01371
01372 private void removeUnchecked() throws Exception
01373 {
01374 deleteDirectoryTree(m_dir);
01375 }
01376
01377
01378
01379
01380
01381 private static class PrivilegedAction implements PrivilegedExceptionAction
01382 {
01383 private static final int INITIALIZE_ACTION = 0;
01384 private static final int UPDATE_ACTION = 1;
01385 private static final int PURGE_ACTION = 2;
01386 private static final int REMOVE_ACTION = 3;
01387 private static final int GET_REVISION_COUNT_ACTION = 4;
01388 private static final int GET_LOCATION_ACTION = 5;
01389 private static final int GET_PERSISTENT_STATE_ACTION = 6;
01390 private static final int SET_PERSISTENT_STATE_ACTION = 7;
01391 private static final int GET_START_LEVEL_ACTION = 8;
01392 private static final int SET_START_LEVEL_ACTION = 9;
01393 private static final int OPEN_BUNDLE_JAR_ACTION = 10;
01394 private static final int CREATE_DATA_DIR_ACTION = 11;
01395 private static final int GET_CLASS_PATH_ACTION = 12;
01396 private static final int GET_ACTIVATOR_ACTION = 13;
01397 private static final int SET_ACTIVATOR_ACTION = 14;
01398
01399 private int m_action = 0;
01400 private OpenmisOscarBundleArchive m_archive = null;
01401 private InputStream m_isArg = null;
01402 private String m_strArg = null;
01403 private int m_intArg = 0;
01404 private File m_fileArg = null;
01405 private ClassLoader m_loaderArg = null;
01406 private Object m_objArg = null;
01407
01408 public PrivilegedAction(int action, OpenmisOscarBundleArchive archive)
01409 {
01410 m_action = action;
01411 m_archive = archive;
01412 }
01413
01414 public PrivilegedAction(int action, OpenmisOscarBundleArchive archive, InputStream isArg)
01415 {
01416 m_action = action;
01417 m_archive = archive;
01418 m_isArg = isArg;
01419 }
01420
01421 public PrivilegedAction(int action, OpenmisOscarBundleArchive archive, int intArg)
01422 {
01423 m_action = action;
01424 m_archive = archive;
01425 m_intArg = intArg;
01426 }
01427
01428 public PrivilegedAction(int action, OpenmisOscarBundleArchive archive, File fileArg)
01429 {
01430 m_action = action;
01431 m_archive = archive;
01432 m_fileArg = fileArg;
01433 }
01434
01435 public PrivilegedAction(int action, OpenmisOscarBundleArchive archive, ClassLoader loaderArg)
01436 {
01437 m_action = action;
01438 m_archive = archive;
01439 m_loaderArg = loaderArg;
01440 }
01441
01442 public PrivilegedAction(int action, OpenmisOscarBundleArchive archive, Object objArg)
01443 {
01444 m_action = action;
01445 m_archive = archive;
01446 m_objArg = objArg;
01447 }
01448
01449 public Object run() throws Exception
01450 {
01451 switch (m_action)
01452 {
01453 case INITIALIZE_ACTION:
01454 m_archive.initializeUnchecked(m_isArg);
01455 return null;
01456 case UPDATE_ACTION:
01457 m_archive.updateUnchecked(m_isArg);
01458 return null;
01459 case PURGE_ACTION:
01460 m_archive.purgeUnchecked();
01461 return null;
01462 case REMOVE_ACTION:
01463 m_archive.removeUnchecked();
01464 return null;
01465 case GET_REVISION_COUNT_ACTION:
01466 return new Integer(m_archive.getRevisionCountUnchecked());
01467 case GET_LOCATION_ACTION:
01468 return m_archive.getLocationUnchecked();
01469 case GET_PERSISTENT_STATE_ACTION:
01470 return new Integer(m_archive.getPersistentStateUnchecked());
01471 case SET_PERSISTENT_STATE_ACTION:
01472 m_archive.setPersistentStateUnchecked(m_intArg);
01473 return null;
01474 case GET_START_LEVEL_ACTION:
01475 return new Integer(m_archive.getStartLevelUnchecked());
01476 case SET_START_LEVEL_ACTION:
01477 m_archive.setStartLevelUnchecked(m_intArg);
01478 return null;
01479 case OPEN_BUNDLE_JAR_ACTION:
01480 return m_archive.openBundleJarUnchecked(m_fileArg);
01481 case CREATE_DATA_DIR_ACTION:
01482 m_archive.createDataDirectoryUnchecked(m_fileArg);
01483 return null;
01484 case GET_CLASS_PATH_ACTION:
01485 return m_archive.getClassPathUnchecked(m_intArg);
01486 case GET_ACTIVATOR_ACTION:
01487 return m_archive.getActivatorUnchecked(m_loaderArg);
01488 case SET_ACTIVATOR_ACTION:
01489 m_archive.setActivatorUnchecked(m_objArg);
01490 return null;
01491 }
01492
01493 throw new IllegalArgumentException("Invalid action specified.");
01494 }
01495 }
01496 }