blob: 7a1772ce1af6a893287223983e5eb2ffa2a487bc [file] [log] [blame]
Karl Pauls9647e842007-02-12 23:46:56 +00001/*
Richard S. Hallb3951672006-09-19 17:04:53 +00002 * 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
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00009 *
Richard S. Hallb3951672006-09-19 17:04:53 +000010 * http://www.apache.org/licenses/LICENSE-2.0
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000011 *
Richard S. Hallb3951672006-09-19 17:04:53 +000012 * 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.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000018 */
19package org.apache.felix.framework.cache;
20
Carsten Ziegeler37d2c292007-08-15 10:03:15 +000021import java.io.File;
22import java.io.IOException;
23import java.io.InputStream;
24import java.util.ArrayList;
25import java.util.List;
26import java.util.Map;
27import java.util.jar.Manifest;
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000028
29import org.apache.felix.framework.Logger;
Richard S. Hall78605422006-12-18 20:47:55 +000030import org.apache.felix.framework.util.FelixConstants;
31import org.apache.felix.framework.util.StringMap;
32import org.apache.felix.framework.util.manifestparser.ManifestParser;
Carsten Ziegeler37d2c292007-08-15 10:03:15 +000033import org.apache.felix.moduleloader.DirectoryContent;
34import org.apache.felix.moduleloader.IContent;
35import org.apache.felix.moduleloader.JarContent;
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000036
37/**
38 * <p>
39 * This class implements a bundle archive revision for exploded bundle
40 * JAR files. It uses the specified location directory "in-place" to
41 * execute the bundle and does not copy the bundle content at all.
42 * </p>
43**/
44class DirectoryRevision extends BundleRevision
45{
Karl Pauls836bb402006-08-24 12:39:46 +000046 private static final transient String BUNDLE_JAR_FILE = "bundle.jar";
47
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000048 private File m_refDir = null;
49 private Map m_header = null;
50
51 public DirectoryRevision(
Karl Pauls836bb402006-08-24 12:39:46 +000052 Logger logger, File revisionRootDir, String location) throws Exception
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000053 {
54 super(logger, revisionRootDir, location);
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +000055 m_refDir = new File(location.substring(
Richard S. Hall04bdbb12006-03-15 14:26:15 +000056 location.indexOf(BundleArchive.FILE_PROTOCOL)
57 + BundleArchive.FILE_PROTOCOL.length()));
Richard S. Hall5d9b9242006-07-20 13:20:05 +000058
59 // If the revision directory exists, then we don't
60 // need to initialize since it has already been done.
Carsten Ziegeler37d2c292007-08-15 10:03:15 +000061 if (BundleCache.getSecureAction().fileExists(this.getRevisionRootDir()))
Richard S. Hall5d9b9242006-07-20 13:20:05 +000062 {
63 return;
64 }
65
66 // Create revision directory, we only need this to store the
67 // revision location, since nothing else needs to be extracted
68 // since we are referencing a read directory already.
Carsten Ziegeler37d2c292007-08-15 10:03:15 +000069 if (!BundleCache.getSecureAction().mkdir(this.getRevisionRootDir()))
Richard S. Hall5d9b9242006-07-20 13:20:05 +000070 {
Carsten Ziegeler37d2c292007-08-15 10:03:15 +000071 this.getLogger().log(
Richard S. Hall5d9b9242006-07-20 13:20:05 +000072 Logger.LOG_ERROR,
Carsten Ziegeler37d2c292007-08-15 10:03:15 +000073 this.getClass().getName() + ": Unable to create revision directory.");
Richard S. Hall5d9b9242006-07-20 13:20:05 +000074 throw new IOException("Unable to create archive directory.");
75 }
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000076 }
77
78 public synchronized Map getManifestHeader()
79 throws Exception
80 {
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +000081 if (m_header != null)
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000082 {
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +000083 return m_header;
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000084 }
85
86 // Read the header file from the reference directory.
87 InputStream is = null;
88
89 try
90 {
91 // Open manifest file.
Richard S. Hall04bdbb12006-03-15 14:26:15 +000092 is = BundleCache.getSecureAction()
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +000093 .getFileInputStream(new File(m_refDir, "META-INF/MANIFEST.MF"));
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000094 // Error if no jar file.
95 if (is == null)
96 {
97 throw new IOException("No manifest file found.");
98 }
99
100 // Get manifest.
101 Manifest mf = new Manifest(is);
102 // Create a case insensitive map of manifest attributes.
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +0000103 m_header = new StringMap(mf.getMainAttributes(), false);
104 return m_header;
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000105 }
106 finally
107 {
108 if (is != null) is.close();
109 }
110 }
111
112 public IContent getContent() throws Exception
113 {
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +0000114 return new DirectoryContent(m_refDir);
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000115 }
116
117 public synchronized IContent[] getContentPath() throws Exception
118 {
119 // Creating the content path entails examining the bundle's
120 // class path to determine whether the bundle JAR file itself
121 // is on the bundle's class path and then creating content
122 // objects for everything on the class path.
Karl Pauls836bb402006-08-24 12:39:46 +0000123
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000124 // Get the bundle's manifest header.
Carsten Ziegeler37d2c292007-08-15 10:03:15 +0000125 Map map = this.getManifestHeader();
Karl Pauls836bb402006-08-24 12:39:46 +0000126
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000127 // Find class path meta-data.
128 String classPath = (map == null)
129 ? null : (String) map.get(FelixConstants.BUNDLE_CLASSPATH);
Karl Pauls836bb402006-08-24 12:39:46 +0000130
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000131 // Parse the class path into strings.
Richard S. Hall78605422006-12-18 20:47:55 +0000132 String[] classPathStrings = ManifestParser.parseDelimitedString(
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000133 classPath, FelixConstants.CLASS_PATH_SEPARATOR);
Karl Pauls836bb402006-08-24 12:39:46 +0000134
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000135 if (classPathStrings == null)
136 {
137 classPathStrings = new String[0];
138 }
Karl Pauls836bb402006-08-24 12:39:46 +0000139
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000140 // Create the bundles class path.
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +0000141 IContent self = new DirectoryContent(m_refDir);
Richard S. Hall77db1812006-10-17 15:05:23 +0000142 List contentList = new ArrayList();
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000143 for (int i = 0; i < classPathStrings.length; i++)
144 {
145 if (classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT))
146 {
Richard S. Hall77db1812006-10-17 15:05:23 +0000147 contentList.add(self);
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000148 }
149 else
150 {
151 // Determine if the class path entry is a file or directory.
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +0000152 File file = new File(m_refDir, classPathStrings[i]);
Richard S. Hall04bdbb12006-03-15 14:26:15 +0000153 if (BundleCache.getSecureAction().isFileDirectory(file))
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000154 {
Richard S. Hall77db1812006-10-17 15:05:23 +0000155 contentList.add(new DirectoryContent(file));
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000156 }
157 else
158 {
Richard S. Hall77db1812006-10-17 15:05:23 +0000159 // Ignore any entries that do not exist per the spec.
160 if (BundleCache.getSecureAction().fileExists(file))
161 {
162 contentList.add(new JarContent(file));
163 }
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000164 }
165 }
166 }
Karl Pauls836bb402006-08-24 12:39:46 +0000167
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000168 // If there is nothing on the class path, then include
169 // "." by default, as per the spec.
Richard S. Hall77db1812006-10-17 15:05:23 +0000170 if (contentList.size() == 0)
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000171 {
Richard S. Hall4f9905e2006-10-18 14:52:59 +0000172 contentList.add(self);
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000173 }
Karl Pauls836bb402006-08-24 12:39:46 +0000174
Richard S. Hall77db1812006-10-17 15:05:23 +0000175 return (IContent[]) contentList.toArray(new IContent[contentList.size()]);
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000176 }
177
178// TODO: This will need to consider security.
179 public String findLibrary(String libName) throws Exception
180 {
Carsten Ziegeler37d2c292007-08-15 10:03:15 +0000181 return BundleCache.getSecureAction().getAbsolutePath(new File(this.m_refDir, libName));
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000182 }
183
184 public void dispose() throws Exception
185 {
186 // Nothing to dispose of, since we don't maintain any state outside
187 // of the revision directory, which will be automatically deleted
188 // by the parent bundle archive.
189 }
Richard S. Hall4f9905e2006-10-18 14:52:59 +0000190}