Return-Path: Delivered-To: apmail-cxf-commits-archive@www.apache.org Received: (qmail 15902 invoked from network); 1 Sep 2008 15:09:05 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 1 Sep 2008 15:09:05 -0000 Received: (qmail 81254 invoked by uid 500); 1 Sep 2008 15:09:03 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 81196 invoked by uid 500); 1 Sep 2008 15:09:03 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 81186 invoked by uid 99); 1 Sep 2008 15:09:03 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 01 Sep 2008 08:09:03 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 01 Sep 2008 15:08:12 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 568B22388AB4; Mon, 1 Sep 2008 08:08:21 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r690991 [9/20] - in /cxf/sandbox/dosgi: ./ discovery/ discovery/local/ discovery/local/src/ discovery/local/src/main/ discovery/local/src/main/java/ discovery/local/src/main/java/org/ discovery/local/src/main/java/org/apache/ discovery/loca... Date: Mon, 01 Sep 2008 15:08:10 -0000 To: commits@cxf.apache.org From: sergeyb@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080901150821.568B22388AB4@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.cache; + +import java.io.File; +import java.util.Map; + +import org.apache.felix.framework.Logger; +import org.apache.felix.moduleloader.IContent; + +/** + *

+ * This class implements an abstract revision of a bundle archive. A revision + * is an abstraction of a bundle's actual content and is associated with a + * parent bundle archive. A bundle archive may have multiple revisions assocaited + * with it at one time, since updating a bundle results in a new version of the + * bundle's content until the bundle is refreshed. Upon a refresh, then old + * revisions are then purged. This abstract class is the base class for all + * concrete types of revisions, such as ones for a JAR file or directories. All + * revisions are assigned a root directory into which all of their state should + * be stored, if necessary. Clean up of this directory is the responsibility + * of the parent bundle archive and not of the revision itself. + *

+ * @see org.apache.felix.framework.cache.BundleCache + * @see org.apache.felix.framework.cache.BundleArchive +**/ +public abstract class BundleRevision +{ + private Logger m_logger; + private File m_revisionRootDir = null; + private String m_location = null; + + /** + *

+ * This class is abstract and cannot be created. It represents a revision + * of a bundle, i.e., its content. A revision is associated with a particular + * location string, which is typically in URL format. Subclasses of this + * class provide particular functionality, such as a revision in the form + * of a JAR file or a directory. Each revision subclass is expected to use + * the root directory associated with the abstract revision instance to + * store any state; this will ensure that resources used by the revision are + * properly freed when the revision is no longer needed. + *

+ * @param logger a logger for use by the revision. + * @param revisionRootDir the root directory to be used by the revision + * subclass for storing any state. + * @param location the location string associated with the revision. + * @param trustedCaCerts the trusted CA certificates if any. + * @throws Exception if any errors occur. + **/ + public BundleRevision(Logger logger, File revisionRootDir, String location) + throws Exception + { + m_logger = logger; + m_revisionRootDir = revisionRootDir; + m_location = location; + } + + /** + *

+ * Returns the logger for this revision. + *

+ * @return the logger instance for this revision. + **/ + public Logger getLogger() + { + return m_logger; + } + + /** + *

+ * Returns the root directory for this revision. + *

+ * @return the root directory for this revision. + **/ + public File getRevisionRootDir() + { + return m_revisionRootDir; + } + + /** + *

+ * Returns the location string this revision. + *

+ * @return the location string for this revision. + **/ + public String getLocation() + { + return m_location; + } + + /** + *

+ * Returns the main attributes of the JAR file manifest header of the + * revision. The returned map is case insensitive. + *

+ * @return the case-insensitive JAR file manifest header of the revision. + * @throws java.lang.Exception if any error occurs. + **/ + public abstract Map getManifestHeader() throws Exception; + + public abstract IContent getContent() throws Exception; + + /** + *

+ * This method is called when the revision is no longer needed. The directory + * associated with the revision will automatically be removed for each + * revision, so this method only needs to be concerned with other issues, + * such as open files. + *

+ * @throws Exception if any error occurs. + **/ + public abstract void dispose() throws Exception; +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.cache; + +import org.apache.felix.moduleloader.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +public class ContentDirectoryContent implements IContent +{ + private IContent m_content = null; + private String m_rootPath = null; + private boolean m_opened = false; + + public ContentDirectoryContent(IContent content, String path) + { + m_content = content; + // Add a '/' to the end if not present. + m_rootPath = (path.length() > 0) && (path.charAt(path.length() - 1) != '/') + ? path + "/" : path; + } + + public void open() + { + m_content.open(); + m_opened = true; + } + + public synchronized void close() + { + // We do not actually close the associated content + // from which we are filtering our directory because + // we assume that this will be close manually by + // the owner of that content. + m_content = null; + m_opened = false; + } + + public synchronized boolean hasEntry(String name) throws IllegalStateException + { + if (!m_opened) + { + throw new IllegalStateException("ContentDirectoryContent is not open"); + } + + if ((name.length() > 0) && (name.charAt(0) == '/')) + { + name = name.substring(1); + } + + return m_content.hasEntry(m_rootPath + name); + } + + public synchronized Enumeration getEntries() + { + if (!m_opened) + { + throw new IllegalStateException("ContentDirectoryContent is not open"); + } + + return new EntriesEnumeration(m_content.getEntries(), m_rootPath); + } + + public synchronized byte[] getEntryAsBytes(String name) throws IllegalStateException + { + if (!m_opened) + { + throw new IllegalStateException("ContentDirectoryContent is not open"); + } + + if ((name.length() > 0) && (name.charAt(0) == '/')) + { + name = name.substring(1); + } + + return m_content.getEntryAsBytes(m_rootPath + name); + } + + public synchronized InputStream getEntryAsStream(String name) + throws IllegalStateException, IOException + { + if (!m_opened) + { + throw new IllegalStateException("ContentDirectoryContent is not open"); + } + + if ((name.length() > 0) && (name.charAt(0) == '/')) + { + name = name.substring(1); + } + + return m_content.getEntryAsStream(m_rootPath + name); + } + + public IContent getEntryAsContent(String name) + { + if (!m_opened) + { + throw new IllegalStateException("ContentDirectoryContent is not open"); + } + + if ((name.length() > 0) && (name.charAt(0) == '/')) + { + name = name.substring(1); + } + + return m_content.getEntryAsContent(m_rootPath + name); + } + + public String getEntryAsNativeLibrary(String name) + { + if (!m_opened) + { + throw new IllegalStateException("ContentDirectoryContent is not open"); + } + + if ((name.length() > 0) && (name.charAt(0) == '/')) + { + name = name.substring(1); + } + + return m_content.getEntryAsNativeLibrary(m_rootPath + name); + } + + public String toString() + { + return "CONTENT DIR " + m_rootPath + " (" + m_content + ")"; + } + + private static class EntriesEnumeration implements Enumeration + { + private Enumeration m_enumeration = null; + private String m_rootPath = null; + private String m_nextEntry = null; + + public EntriesEnumeration(Enumeration enumeration, String rootPath) + { + m_enumeration = enumeration; + m_rootPath = rootPath; + m_nextEntry = findNextEntry(); + } + + public boolean hasMoreElements() + { + return (m_nextEntry != null); + } + + public Object nextElement() + { + if (m_nextEntry == null) + { + throw new NoSuchElementException("No more elements."); + } + String currentEntry = m_nextEntry; + m_nextEntry = findNextEntry(); + return currentEntry; + } + + private String findNextEntry() + { + // Find next entry that is inside the root directory. + while (m_enumeration.hasMoreElements()) + { + String next = (String) m_enumeration.nextElement(); + if (next.startsWith(m_rootPath) && !next.equals(m_rootPath)) + { + // Strip off the root directory. + return next.substring(m_rootPath.length()); + } + } + return null; + } + } +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.cache; + +import org.apache.felix.moduleloader.*; +import java.io.*; +import java.util.*; +import org.apache.felix.framework.Logger; + +public class DirectoryContent implements IContent +{ + private static final int BUFSIZE = 4096; + private static final transient String EMBEDDED_DIRECTORY = "-embedded"; + private static final transient String LIBRARY_DIRECTORY = "lib"; + + private Logger m_logger; + private Object m_revisionLock; + private File m_rootDir; + private File m_dir; + private boolean m_opened = false; + + public DirectoryContent(Logger logger, Object revisionLock, File rootDir, File dir) + { + m_logger = logger; + m_revisionLock = revisionLock; + m_rootDir = rootDir; + m_dir = dir; + } + + public void open() + { + m_opened = true; + } + + public synchronized void close() + { + m_opened = false; + } + + public synchronized boolean hasEntry(String name) throws IllegalStateException + { + if (!m_opened) + { + throw new IllegalStateException("DirectoryContent is not open"); + } + + if ((name.length() > 0) && (name.charAt(0) == '/')) + { + name = name.substring(1); + } + + return new File(m_dir, name).exists(); + } + + public synchronized Enumeration getEntries() + { + if (!m_opened) + { + throw new IllegalStateException("JarContent is not open"); + } + + // Wrap entries enumeration to filter non-matching entries. + Enumeration e = new EntriesEnumeration(m_dir); + + // Spec says to return null if there are no entries. + return (e.hasMoreElements()) ? e : null; + } + + public synchronized byte[] getEntryAsBytes(String name) throws IllegalStateException + { + if (!m_opened) + { + throw new IllegalStateException("DirectoryContent is not open"); + } + + if ((name.length() > 0) && (name.charAt(0) == '/')) + { + name = name.substring(1); + } + + // Get the embedded resource. + InputStream is = null; + ByteArrayOutputStream baos = null; + + try + { + is = new BufferedInputStream(new FileInputStream(new File(m_dir, name))); + baos = new ByteArrayOutputStream(BUFSIZE); + byte[] buf = new byte[BUFSIZE]; + int n = 0; + while ((n = is.read(buf, 0, buf.length)) >= 0) + { + baos.write(buf, 0, n); + } + return baos.toByteArray(); + + } + catch (Exception ex) + { + return null; + } + finally + { + try + { + if (baos != null) baos.close(); + } + catch (Exception ex) + { + } + try + { + if (is != null) is.close(); + } + catch (Exception ex) + { + } + } + } + + public synchronized InputStream getEntryAsStream(String name) + throws IllegalStateException, IOException + { + if (!m_opened) + { + throw new IllegalStateException("DirectoryContent is not open"); + } + + if ((name.length() > 0) && (name.charAt(0) == '/')) + { + name = name.substring(1); + } + + return new FileInputStream(new File(m_dir, name)); + } + + public synchronized IContent getEntryAsContent(String entryName) + { + if (!m_opened) + { + throw new IllegalStateException("DirectoryContent is not open"); + } + + // Remove any leading slash, since all bundle class path + // entries are relative to the root of the bundle. + entryName = (entryName.startsWith("/")) ? entryName.substring(1) : entryName; + + // Any embedded JAR files will be extracted to the embedded directory. + File embedDir = new File(m_rootDir, m_dir.getName() + EMBEDDED_DIRECTORY); + + // Determine if the entry is an emdedded JAR file or + // directory in the bundle JAR file. Ignore any entries + // that do not exist per the spec. + File file = new File(m_dir, entryName); + if (BundleCache.getSecureAction().isFileDirectory(file)) + { + return new DirectoryContent(m_logger, m_revisionLock, m_rootDir, file); + } + else if (BundleCache.getSecureAction().fileExists(file) + && entryName.endsWith(".jar")) + { + File extractedDir = new File(embedDir, + (entryName.lastIndexOf('/') >= 0) + ? entryName.substring(0, entryName.lastIndexOf('/')) + : entryName); + synchronized (m_revisionLock) + { + if (!BundleCache.getSecureAction().fileExists(extractedDir)) + { + if (!BundleCache.getSecureAction().mkdirs(extractedDir)) + { + m_logger.log( + Logger.LOG_ERROR, + "Unable to extract embedded directory."); + } + } + } + System.out.println("+++ EXTRACTED JAR DIR " + extractedDir); + return new JarContent(m_logger, m_revisionLock, extractedDir, file); + } + + // The entry could not be found, so return null. + return null; + } + +// TODO: This will need to consider security. + public synchronized String getEntryAsNativeLibrary(String name) + { + if (!m_opened) + { + throw new IllegalStateException("DirectoryContent is not open"); + } + + return BundleCache.getSecureAction().getAbsolutePath(new File(m_rootDir, name)); + } + + public String toString() + { + return "DIRECTORY " + m_dir; + } + + private static class EntriesEnumeration implements Enumeration + { + private File m_dir = null; + private File[] m_children = null; + private int m_counter = 0; + + public EntriesEnumeration(File dir) + { + m_dir = dir; + m_children = listFilesRecursive(m_dir); + } + + public boolean hasMoreElements() + { + return (m_children != null) && (m_counter < m_children.length); + } + + public Object nextElement() + { + if ((m_children == null) || (m_counter >= m_children.length)) + { + throw new NoSuchElementException("No more entry paths."); + } + + // Convert the file separator character to slashes. + String abs = m_children[m_counter].getAbsolutePath() + .replace(File.separatorChar, '/'); + + // Remove the leading path of the reference directory, since the + // entry paths are supposed to be relative to the root. + StringBuffer sb = new StringBuffer(abs); + sb.delete(0, m_dir.getAbsolutePath().length() + 1); + // Add a '/' to the end of directory entries. + if (m_children[m_counter].isDirectory()) + { + sb.append('/'); + } + m_counter++; + return sb.toString(); + } + + public File[] listFilesRecursive(File dir) + { + File[] children = dir.listFiles(); + File[] combined = children; + for (int i = 0; i < children.length; i++) + { + if (children[i].isDirectory()) + { + File[] grandchildren = listFilesRecursive(children[i]); + if (grandchildren.length > 0) + { + File[] tmp = new File[combined.length + grandchildren.length]; + System.arraycopy(combined, 0, tmp, 0, combined.length); + System.arraycopy(grandchildren, 0, tmp, combined.length, grandchildren.length); + combined = tmp; + } + } + } + return combined; + } + } +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.cache; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.jar.Manifest; + +import org.apache.felix.framework.Logger; +import org.apache.felix.framework.util.FelixConstants; +import org.apache.felix.framework.util.StringMap; +import org.apache.felix.framework.util.manifestparser.ManifestParser; +import org.apache.felix.framework.cache.DirectoryContent; +import org.apache.felix.moduleloader.IContent; +import org.apache.felix.framework.cache.JarContent; + +/** + *

+ * This class implements a bundle archive revision for exploded bundle + * JAR files. It uses the specified location directory "in-place" to + * execute the bundle and does not copy the bundle content at all. + *

+**/ +class DirectoryRevision extends BundleRevision +{ + private File m_refDir = null; + private Map m_header = null; + + public DirectoryRevision( + Logger logger, File revisionRootDir, String location) throws Exception + { + super(logger, revisionRootDir, location); + m_refDir = new File(location.substring( + location.indexOf(BundleArchive.FILE_PROTOCOL) + + BundleArchive.FILE_PROTOCOL.length())); + + // If the revision directory exists, then we don't + // need to initialize since it has already been done. + if (BundleCache.getSecureAction().fileExists(getRevisionRootDir())) + { + return; + } + + // Create revision directory, we only need this to store the + // revision location, since nothing else needs to be extracted + // since we are referencing a read directory already. + if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir())) + { + getLogger().log( + Logger.LOG_ERROR, + getClass().getName() + ": Unable to create revision directory."); + throw new IOException("Unable to create archive directory."); + } + } + + public synchronized Map getManifestHeader() + throws Exception + { + if (m_header != null) + { + return m_header; + } + + // Read the header file from the reference directory. + InputStream is = null; + + try + { + // Open manifest file. + is = BundleCache.getSecureAction() + .getFileInputStream(new File(m_refDir, "META-INF/MANIFEST.MF")); + // Error if no jar file. + if (is == null) + { + throw new IOException("No manifest file found."); + } + + // Get manifest. + Manifest mf = new Manifest(is); + // Create a case insensitive map of manifest attributes. + m_header = new StringMap(mf.getMainAttributes(), false); + return m_header; + } + finally + { + if (is != null) is.close(); + } + } + + public synchronized IContent getContent() throws Exception + { + return new DirectoryContent(getLogger(), this, getRevisionRootDir(), m_refDir); + } + + public void dispose() throws Exception + { + // Nothing to dispose of, since we don't maintain any state outside + // of the revision directory, which will be automatically deleted + // by the parent bundle archive. + } +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,596 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.cache; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import org.apache.felix.framework.Logger; +import org.apache.felix.framework.util.JarFileX; +import org.apache.felix.moduleloader.IContent; + +public class JarContent implements IContent +{ + private static final int BUFSIZE = 4096; + private static final transient String LEGACY_EMBEDDED_DIRECTORY = "embedded"; + private static final transient String EMBEDDED_DIRECTORY = "-embedded"; + private static final transient String LIBRARY_DIRECTORY = "lib"; + + private final Logger m_logger; + private final Object m_revisionLock; + private final File m_rootDir; + private final File m_file; + private JarFileX m_jarFile = null; + // TODO: CACHE - It would be nice to eventually remove this legacy flag. + private final boolean m_legacy; + private boolean m_opened = false; + + public JarContent(Logger logger, Object revisionLock, File rootDir, File file) + { + m_logger = logger; + m_revisionLock = revisionLock; + m_rootDir = rootDir; + m_file = file; + m_legacy = false; + } + + // This is only used by JarRevision. + public JarContent(Logger logger, Object revisionLock, File rootDir, File file, boolean legacy) + { + m_logger = logger; + m_revisionLock = revisionLock; + m_rootDir = rootDir; + m_file = file; + m_legacy = legacy; + } + + protected void finalize() + { + if (m_jarFile != null) + { + try + { + m_jarFile.close(); + } + catch (IOException ex) + { + // Not much we can do, so ignore it. + } + } + } + + public synchronized void open() + { + m_opened = true; + } + + public synchronized void close() + { + try + { + if (m_jarFile != null) + { + m_jarFile.close(); + } + } + catch (Exception ex) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Unable to open JAR file.", ex); + } + + m_jarFile = null; + m_opened = false; + } + + public synchronized boolean hasEntry(String name) throws IllegalStateException + { + if (!m_opened) + { + throw new IllegalStateException("JarContent is not open"); + } + + // Open JAR file if not already opened. + if (m_jarFile == null) + { + try + { + openJarFile(); + } + catch (IOException ex) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Unable to open JAR file.", ex); + return false; + } + } + + try + { + ZipEntry ze = m_jarFile.getEntry(name); + return ze != null; + } + catch (Exception ex) + { + return false; + } + finally + { + } + } + + public synchronized Enumeration getEntries() + { + if (!m_opened) + { + throw new IllegalStateException("JarContent is not open"); + } + + // Open JAR file if not already opened. + if (m_jarFile == null) + { + try + { + openJarFile(); + } + catch (IOException ex) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Unable to open JAR file.", ex); + return null; + } + } + + // Wrap entries enumeration to filter non-matching entries. + Enumeration e = new EntriesEnumeration(m_jarFile.entries()); + + // Spec says to return null if there are no entries. + return (e.hasMoreElements()) ? e : null; + } + + public synchronized byte[] getEntryAsBytes(String name) throws IllegalStateException + { + if (!m_opened) + { + throw new IllegalStateException("JarContent is not open"); + } + + // Open JAR file if not already opened. + if (m_jarFile == null) + { + try + { + openJarFile(); + } + catch (IOException ex) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Unable to open JAR file.", ex); + return null; + } + } + + // Get the embedded resource. + InputStream is = null; + ByteArrayOutputStream baos = null; + + try + { + ZipEntry ze = m_jarFile.getEntry(name); + if (ze == null) + { + return null; + } + is = m_jarFile.getInputStream(ze); + if (is == null) + { + return null; + } + baos = new ByteArrayOutputStream(BUFSIZE); + byte[] buf = new byte[BUFSIZE]; + int n = 0; + while ((n = is.read(buf, 0, buf.length)) >= 0) + { + baos.write(buf, 0, n); + } + return baos.toByteArray(); + + } + catch (Exception ex) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Unable to read bytes.", ex); + return null; + } + finally + { + try + { + if (baos != null) baos.close(); + } + catch (Exception ex) + { + } + try + { + if (is != null) is.close(); + } + catch (Exception ex) + { + } + } + } + + public synchronized InputStream getEntryAsStream(String name) + throws IllegalStateException, IOException + { + if (!m_opened) + { + throw new IllegalStateException("JarContent is not open"); + } + + // Open JAR file if not already opened. + if (m_jarFile == null) + { + try + { + openJarFile(); + } + catch (IOException ex) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Unable to open JAR file.", ex); + return null; + } + } + + // Get the embedded resource. + InputStream is = null; + + try + { + ZipEntry ze = m_jarFile.getEntry(name); + if (ze == null) + { + return null; + } + is = m_jarFile.getInputStream(ze); + if (is == null) + { + return null; + } + } + catch (Exception ex) + { + return null; + } + + return is; + } + + public synchronized IContent getEntryAsContent(String entryName) + { + if (!m_opened) + { + throw new IllegalStateException("JarContent is not open"); + } + + // Open JAR file if not already opened. + if (m_jarFile == null) + { + try + { + openJarFile(); + } + catch (IOException ex) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Unable to open JAR file.", ex); + return null; + } + + } + + // Remove any leading slash. + entryName = (entryName.startsWith("/")) ? entryName.substring(1) : entryName; + + // Any embedded JAR files will be extracted to the embedded directory. + // Since embedded JAR file names may clash when extracting from multiple + // embedded JAR files, the embedded directory is per embedded JAR file. + // For backwards compatibility purposes, don't use the file cache name + // for the root bundle JAR file. + File embedDir; + if (m_legacy) + { + embedDir = new File(m_rootDir, LEGACY_EMBEDDED_DIRECTORY); + } + else + { + embedDir = new File(m_rootDir, m_file.getName() + EMBEDDED_DIRECTORY); + } + + // Find the entry in the JAR file and create the + // appropriate content type for it. + + // Determine if the entry is an emdedded JAR file or + // directory in the bundle JAR file. Ignore any entries + // that do not exist per the spec. + ZipEntry ze = m_jarFile.getEntry(entryName); + if ((ze != null) && ze.isDirectory()) + { + File extractedDir = new File(embedDir, entryName); + + // Extracting an embedded directory file impacts all other existing + // contents for this revision, so we have to grab the revision + // lock first before trying to create a directory for an embedded + // directory to avoid a race condition. + synchronized (m_revisionLock) + { + if (!BundleCache.getSecureAction().fileExists(extractedDir)) + { + if (!BundleCache.getSecureAction().mkdirs(extractedDir)) + { + m_logger.log( + Logger.LOG_ERROR, + "Unable to extract embedded directory."); + } + } + } + return new ContentDirectoryContent(this, entryName); + } + else if ((ze != null) && ze.getName().endsWith(".jar")) + { + File extractedJar = new File(embedDir, entryName); + + // Extracting the embedded JAR file impacts all other existing + // contents for this revision, so we have to grab the revision + // lock first before trying to extract the embedded JAR file + // to avoid a race condition. + synchronized (m_revisionLock) + { + if (!BundleCache.getSecureAction().fileExists(extractedJar)) + { + try + { + extractEmbeddedJar(entryName); + } + catch (Exception ex) + { + m_logger.log( + Logger.LOG_ERROR, + "Unable to extract embedded JAR file.", ex); + } + } + } + return new JarContent( + m_logger, m_revisionLock, extractedJar.getParentFile(), extractedJar); + } + + // The entry could not be found, so return null. + return null; + } + +// TODO: This will need to consider security. + public synchronized String getEntryAsNativeLibrary(String name) + { + if (!m_opened) + { + throw new IllegalStateException("JarContent is not open"); + } + + // Open JAR file if not already opened. + if (m_jarFile == null) + { + try + { + openJarFile(); + } + catch (IOException ex) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Unable to open JAR file.", ex); + return null; + } + } + + // Get bundle lib directory. + File libDir = new File(m_rootDir, LIBRARY_DIRECTORY); + // Get lib file. + File libFile = new File(libDir, File.separatorChar + name); + // Make sure that the library's parent directory exists; + // it may be in a sub-directory. + libDir = libFile.getParentFile(); + if (!BundleCache.getSecureAction().fileExists(libDir)) + { + if (!BundleCache.getSecureAction().mkdirs(libDir)) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Unable to create library directory."); + return null; + } + } + // Extract the library from the JAR file if it does not + // already exist. + if (!BundleCache.getSecureAction().fileExists(libFile)) + { + InputStream is = null; + + try + { + ZipEntry ze = m_jarFile.getEntry(name); + if (ze == null) + { + return null; + } + is = new BufferedInputStream( + m_jarFile.getInputStream(ze), BundleCache.BUFSIZE); + if (is == null) + { + throw new IOException("No input stream: " + name); + } + + // Create the file. + BundleCache.copyStreamToFile(is, libFile); + } + catch (Exception ex) + { + m_logger.log( + Logger.LOG_ERROR, + "JarContent: Extracting native library.", ex); + } + finally + { + try + { + if (is != null) is.close(); + } + catch (IOException ex) + { + // Not much we can do. + } + } + } + + return BundleCache.getSecureAction().getAbsolutePath(libFile); + } + + public String toString() + { + return "JAR " + m_file.getPath(); + } + + public File getFile() + { + return m_file; + } + + private void openJarFile() throws IOException + { + if (m_jarFile == null) + { + m_jarFile = BundleCache.getSecureAction().openJAR(m_file); + } + } + + /** + * This method extracts an embedded JAR file from the bundle's + * JAR file. + * @param id the identifier of the bundle that owns the embedded JAR file. + * @param jarPath the path to the embedded JAR file inside the bundle JAR file. + **/ + private void extractEmbeddedJar(String jarPath) + throws Exception + { + // Remove leading slash if present. + jarPath = (jarPath.length() > 0) && (jarPath.charAt(0) == '/') + ? jarPath.substring(1) : jarPath; + + // Any embedded JAR files will be extracted to the embedded directory. + // Since embedded JAR file names may clash when extracting from multiple + // embedded JAR files, the embedded directory is per embedded JAR file. + // For backwards compatibility purposes, don't use the file cache name + // for the root bundle JAR file. + File embedDir; + if (m_legacy) + { + embedDir = new File(m_rootDir, LEGACY_EMBEDDED_DIRECTORY); + } + else + { + embedDir = new File(m_rootDir, m_file.getName() + EMBEDDED_DIRECTORY); + } + File jarFile = new File(embedDir, jarPath); + + if (!BundleCache.getSecureAction().fileExists(jarFile)) + { + InputStream is = null; + try + { + // Make sure class path entry is a JAR file. + ZipEntry ze = m_jarFile.getEntry(jarPath); + if (ze == null) + { + return; + } + // If the zip entry is a directory, then ignore it since + // we don't need to extact it; otherwise, it points to an + // embedded JAR file, so extract it. + else if (!ze.isDirectory()) + { + // Make sure that the embedded JAR's parent directory exists; + // it may be in a sub-directory. + File jarDir = jarFile.getParentFile(); + if (!BundleCache.getSecureAction().fileExists(jarDir)) + { + if (!BundleCache.getSecureAction().mkdirs(jarDir)) + { + throw new IOException("Unable to create embedded JAR directory."); + } + } + + // Extract embedded JAR into its directory. + is = new BufferedInputStream(m_jarFile.getInputStream(ze), BundleCache.BUFSIZE); + if (is == null) + { + throw new IOException("No input stream: " + jarPath); + } + // Copy the file. + BundleCache.copyStreamToFile(is, jarFile); + } + } + finally + { + if (is != null) is.close(); + } + } + } + + private static class EntriesEnumeration implements Enumeration + { + private Enumeration m_enumeration = null; + + public EntriesEnumeration(Enumeration enumeration) + { + m_enumeration = enumeration; + } + + public boolean hasMoreElements() + { + return m_enumeration.hasMoreElements(); + } + + public Object nextElement() + { + return ((ZipEntry) m_enumeration.nextElement()).getName(); + } + } +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.cache; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.Map; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +import org.apache.felix.framework.Logger; +import org.apache.felix.framework.util.StringMap; +import org.apache.felix.framework.util.Util; +import org.apache.felix.moduleloader.IContent; + +/** + *

+ * This class implements a bundle archive revision for a standard bundle + * JAR file. The specified location is the URL of the JAR file. By default, + * the associated JAR file is copied into the revision's directory on the + * file system, but it is possible to mark the JAR as 'by reference', which + * will result in the bundle JAR be used 'in place' and not being copied. In + * either case, some of the contents may be extracted into the revision + * directory, such as embedded JAR files and native libraries. + *

+**/ +class JarRevision extends BundleRevision +{ + private static final transient String BUNDLE_JAR_FILE = "bundle.jar"; + + private File m_bundleFile = null; + private Map m_header = null; + + public JarRevision( + Logger logger, File revisionRootDir, String location, boolean byReference) + throws Exception + { + this(logger, revisionRootDir, location, byReference, null); + } + + public JarRevision( + Logger logger, File revisionRootDir, String location, + boolean byReference, InputStream is) + throws Exception + { + super(logger, revisionRootDir, location); + + if (byReference) + { + m_bundleFile = new File(location.substring( + location.indexOf(BundleArchive.FILE_PROTOCOL) + + BundleArchive.FILE_PROTOCOL.length())); + } + else + { + m_bundleFile = new File(getRevisionRootDir(), BUNDLE_JAR_FILE); + } + + // Save and process the bundle JAR. + initialize(byReference, is); + } + + public synchronized Map getManifestHeader() throws Exception + { + if (m_header != null) + { + return m_header; + } + + // Get the embedded resource. + JarFile jarFile = null; + + try + { + // Open bundle JAR file. + jarFile = BundleCache.getSecureAction().openJAR(m_bundleFile); + // Error if no jar file. + if (jarFile == null) + { + throw new IOException("No JAR file found."); + } + // Get manifest. + Manifest mf = jarFile.getManifest(); + // Create a case insensitive map of manifest attributes. + m_header = new StringMap(mf.getMainAttributes(), false); + return m_header; + + } + finally + { + if (jarFile != null) jarFile.close(); + } + } + + public synchronized IContent getContent() throws Exception + { + return new JarContent(getLogger(), this, getRevisionRootDir(), m_bundleFile, true); + } + + public void dispose() throws Exception + { + // Nothing to dispose of, since we don't maintain any state outside + // of the revision directory, which will be automatically deleted + // by the parent bundle archive. + } + + // + // Private methods. + // + + private void initialize(boolean byReference, InputStream is) + throws Exception + { + try + { + // If the revision directory exists, then we don't + // need to initialize since it has already been done. + if (BundleCache.getSecureAction().fileExists(getRevisionRootDir())) + { + return; + } + + // Create revision directory. + if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir())) + { + getLogger().log( + Logger.LOG_ERROR, + getClass().getName() + ": Unable to create revision directory."); + throw new IOException("Unable to create archive directory."); + } + + if (!byReference) + { + if (is == null) + { + // Do it the manual way to have a chance to + // set request properties such as proxy auth. + URL url = new URL(getLocation()); + URLConnection conn = url.openConnection(); + + // Support for http proxy authentication. + String auth = BundleCache.getSecureAction() + .getSystemProperty("http.proxyAuth", null); + if ((auth != null) && (auth.length() > 0)) + { + if ("http".equals(url.getProtocol()) || + "https".equals(url.getProtocol())) + { + String base64 = Util.base64Encode(auth); + conn.setRequestProperty( + "Proxy-Authorization", "Basic " + base64); + } + } + is = BundleCache.getSecureAction().getURLConnectionInputStream(conn); + } + + // Save the bundle jar file. + BundleCache.copyStreamToFile(is, m_bundleFile); + } + } + finally + { + if (is != null) is.close(); + } + } +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/FelixBundleContext.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/FelixBundleContext.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/FelixBundleContext.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/FelixBundleContext.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.ext; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; + +public interface FelixBundleContext extends BundleContext +{ + public void addRequirement(String s) throws BundleException; + public void removeRequirement() throws BundleException; + public void addCapability() throws BundleException; + public void removeCapability() throws BundleException; +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/FelixBundleContext.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/FelixBundleContext.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/SecurityProvider.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/SecurityProvider.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/SecurityProvider.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/SecurityProvider.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.ext; + +import java.security.Permission; +import java.security.ProtectionDomain; + +import org.osgi.framework.Bundle; + +public interface SecurityProvider +{ + boolean hasBundlePermission(ProtectionDomain pd, Permission p, boolean direct); + + Object getSignerMatcher(Bundle bundle); + + void checkBundle(Bundle bundle) throws Exception; +} Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/SecurityProvider.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/ext/SecurityProvider.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,326 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.searchpolicy; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.URL; +import java.security.ProtectionDomain; +import java.security.SecureClassLoader; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import org.apache.felix.framework.util.Util; +import org.apache.felix.moduleloader.IContent; +import org.apache.felix.moduleloader.IContentLoader; +import org.apache.felix.framework.cache.JarContent; +import org.apache.felix.moduleloader.ResourceNotFoundException; + +public class ContentClassLoader extends SecureClassLoader +{ + private static final Constructor m_dexFileClassConstructor; + private static final Method m_dexFileClassLoadClass; + static + { + Constructor dexFileClassConstructor = null; + Method dexFileClassLoadClass = null; + try + { + Class dexFileClass = Class.forName("android.dalvik.DexFile"); + dexFileClassConstructor = dexFileClass.getConstructor( + new Class[] { java.io.File.class }); + dexFileClassLoadClass = dexFileClass.getMethod("loadClass", + new Class[] { String.class, ClassLoader.class }); + } + catch (Exception ex) + { + dexFileClassConstructor = null; + dexFileClassLoadClass = null; + } + m_dexFileClassConstructor = dexFileClassConstructor; + m_dexFileClassLoadClass = dexFileClassLoadClass; + } + + private ContentLoaderImpl m_contentLoader = null; + private ProtectionDomain m_protectionDomain = null; + private Map m_jarContentToDexFile = null; + + public ContentClassLoader(ContentLoaderImpl contentLoader, + ProtectionDomain protectionDomain) + { + m_contentLoader = contentLoader; + m_protectionDomain = protectionDomain; + if (m_dexFileClassConstructor != null) + { + m_jarContentToDexFile = new HashMap(); + } + } + + public IContentLoader getContentLoader() + { + return m_contentLoader; + } + + protected Class loadClassFromModule(String name) + throws ClassNotFoundException + { + // Ask the search policy for the clas before consulting the module. + Class clazz = findClass(name); + + // If not found, then throw an exception. + if (clazz == null) + { + throw new ClassNotFoundException(name); + } + return clazz; + } + + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + Class clazz = null; + + // Make sure the class was not already loaded. + synchronized (this) + { + clazz = findLoadedClass(name); + } + + if (clazz == null) + { + // Ask the search policy for the class. + clazz = m_contentLoader.getSearchPolicy().findClass(name); + } + + // If still not found, then throw an exception. + if (clazz == null) + { + throw new ClassNotFoundException(name); + } + // Otherwise resolve the class. + if (resolve) + { + resolveClass(clazz); + } + return clazz; + } + + protected Class findClass(String name) throws ClassNotFoundException + { + // Do a quick check here to see if we can short-circuit this + // entire process if the class was already loaded. + Class clazz = null; + synchronized (this) + { + clazz = findLoadedClass(name); + } + + // Search for class in module. + if (clazz == null) + { + String actual = name.replace('.', '/') + ".class"; + + byte[] bytes = null; + + IContent content = null; + // Check the module class path. + for (int i = 0; + (bytes == null) && + (i < m_contentLoader.getClassPath().length); i++) + { + bytes = m_contentLoader.getClassPath()[i].getEntryAsBytes(actual); + content = m_contentLoader.getClassPath()[i]; + } + + if (bytes != null) + { + // Before we actually attempt to define the class, grab + // the lock for this class loader and make sure than no + // other thread has defined this class in the meantime. + synchronized (this) + { + clazz = findLoadedClass(name); + + if (clazz == null) + { + // We need to try to define a Package object for the class + // before we call defineClass(). Get the package name and + // see if we have already created the package. + String pkgName = Util.getClassPackage(name); + if (pkgName.length() > 0) + { + if (getPackage(pkgName) == null) + { + Object[] params = + m_contentLoader.getSearchPolicy() + .definePackage(pkgName); + if (params != null) + { + definePackage( + pkgName, + (String) params[0], + (String) params[1], + (String) params[2], + (String) params[3], + (String) params[4], + (String) params[5], + null); + } + else + { + definePackage(pkgName, null, null, + null, null, null, null, null); + } + } + } + + // If we can load the class from a dex file do so + if (content instanceof JarContent) + { + try + { + clazz = getDexFileClass((JarContent) content, name, this); + } + catch (Exception ex) + { + // Looks like we can't + } + } + + if (clazz == null) + { + // If we have a security context, then use it to + // define the class with it for security purposes, + // otherwise define the class without a protection domain. + if (m_protectionDomain != null) + { + clazz = defineClass(name, bytes, 0, bytes.length, + m_protectionDomain); + } + else + { + clazz = defineClass(name, bytes, 0, bytes.length); + } + } + } + } + } + } + + return clazz; + } + + private Class getDexFileClass(JarContent content, String name, ClassLoader loader) + throws Exception + { + if (m_jarContentToDexFile == null) + { + return null; + } + + Object dexFile = null; + + if (!m_jarContentToDexFile.containsKey(content)) + { + try + { + dexFile = m_dexFileClassConstructor.newInstance( + new Object[] { content.getFile() }); + } + finally + { + m_jarContentToDexFile.put(content, dexFile); + } + } + else + { + dexFile = m_jarContentToDexFile.get(content); + } + + if (dexFile != null) + { + return (Class) m_dexFileClassLoadClass.invoke(dexFile, + new Object[] { name.replace('.','/'), loader }); + } + return null; + } + + public URL getResourceFromModule(String name) + { + try + { + return findResource(name); + } + catch (Throwable th) + { + // Ignore and just return null. + } + return null; + } + + public URL getResource(String name) + { + // Ask the search policy for the class before consulting the module. + try + { + return m_contentLoader.getSearchPolicy().findResource(name); + } + catch (ResourceNotFoundException ex) + { + } + return null; + } + + protected URL findResource(String name) + { + // Ask the search policy for the resource. + try + { + return m_contentLoader.getSearchPolicy().findResource(name); + } + catch (ResourceNotFoundException ex) + { + } + return null; + } + + protected Enumeration findResources(String name) + { + // Ask the search policy for the resources. + try + { + return m_contentLoader.getSearchPolicy().findResources(name); + } + catch (ResourceNotFoundException ex) + { + } + return null; + } + + protected String findLibrary(String name) + { + return m_contentLoader.getSearchPolicy().findLibrary(name); + } + + public String toString() + { + return m_contentLoader.toString(); + } +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,362 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.searchpolicy; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import java.util.jar.Manifest; +import org.apache.felix.framework.Logger; +import org.apache.felix.framework.util.FelixConstants; +import org.apache.felix.framework.util.SecureAction; +import org.apache.felix.framework.util.StringMap; +import org.apache.felix.framework.util.manifestparser.ManifestParser; +import org.apache.felix.moduleloader.*; + +public class ContentLoaderImpl implements IContentLoader +{ + private Logger m_logger = null; + private IContent m_content = null; + private IContent[] m_contentPath = null; + private ISearchPolicy m_searchPolicy = null; + private IURLPolicy m_urlPolicy = null; + private ContentClassLoader m_classLoader = null; + private ProtectionDomain m_protectionDomain = null; + private static SecureAction m_secureAction = new SecureAction(); + + public ContentLoaderImpl(Logger logger, IContent content) + { + m_logger = logger; + m_content = content; + } + + public Logger getLogger() + { + return m_logger; + } + + public void open() + { + m_content.open(); + try + { + initializeContentPath(); + } + catch (Exception ex) + { + m_logger.log(Logger.LOG_ERROR, "Unable to initialize content path.", ex); + } + + for (int i = 0; (m_contentPath != null) && (i < m_contentPath.length); i++) + { + m_contentPath[i].open(); + } + } + + public void close() + { + m_content.close(); + for (int i = 0; (m_contentPath != null) && (i < m_contentPath.length); i++) + { + m_contentPath[i].close(); + } + } + + public IContent getContent() + { + return m_content; + } + + public IContent[] getClassPath() + { + return m_contentPath; + } + + public void setSearchPolicy(ISearchPolicy searchPolicy) + { + m_searchPolicy = searchPolicy; + } + + public ISearchPolicy getSearchPolicy() + { + return m_searchPolicy; + } + + public void setURLPolicy(IURLPolicy urlPolicy) + { + m_urlPolicy = urlPolicy; + } + + public IURLPolicy getURLPolicy() + { + return m_urlPolicy; + } + + public synchronized void setSecurityContext(Object securityContext) + { + m_protectionDomain = (ProtectionDomain) securityContext; + } + + public synchronized Object getSecurityContext() + { + return m_protectionDomain; + } + + public Class getClass(String name) + { + synchronized (this) + { + if (m_classLoader == null) + { + m_classLoader = m_secureAction.createContentClassLoader(this, + m_protectionDomain); + } + } + + try + { + return m_classLoader.loadClassFromModule(name); + } + catch (ClassNotFoundException ex) + { + return null; + } + } + + public URL getResource(String name) + { + URL url = null; + + // Remove leading slash, if present, but special case + // "/" so that it returns a root URL...this isn't very + // clean or meaninful, but the Spring guys want it. + if (name.equals("/")) + { + // Just pick a class path index since it doesn't really matter. + url = getURLPolicy().createURL(1, name); + } + else if (name.startsWith("/")) + { + name = name.substring(1); + } + + // Check the module class path. + for (int i = 0; + (url == null) && + (i < getClassPath().length); i++) + { + if (getClassPath()[i].hasEntry(name)) + { + url = getURLPolicy().createURL(i + 1, name); + } + } + + return url; + } + + public Enumeration getResources(String name) + { + Vector v = new Vector(); + + // Special case "/" so that it returns a root URLs for + // each bundle class path entry...this isn't very + // clean or meaningful, but the Spring guys want it. + if (name.equals("/")) + { + for (int i = 0; i < getClassPath().length; i++) + { + v.addElement(getURLPolicy().createURL(i + 1, name)); + } + } + else + { + // Remove leading slash, if present. + if (name.startsWith("/")) + { + name = name.substring(1); + } + + // Check the module class path. + for (int i = 0; i < getClassPath().length; i++) + { + if (getClassPath()[i].hasEntry(name)) + { + // Use the class path index + 1 for creating the path so + // that we can differentiate between module content URLs + // (where the path will start with 0) and module class + // path URLs. + v.addElement(getURLPolicy().createURL(i + 1, name)); + } + } + } + + return v.elements(); + } + + // TODO: API: Investigate how to handle this better, perhaps we need + // multiple URL policies, one for content -- one for class path. + public URL getResourceFromContent(String name) + { + URL url = null; + + // Check for the special case of "/", which represents + // the root of the bundle according to the spec. + if (name.equals("/")) + { + url = getURLPolicy().createURL(0, "/"); + } + + if (url == null) + { + // Remove leading slash, if present. + if (name.startsWith("/")) + { + name = name.substring(1); + } + + // Check the module content. + if (getContent().hasEntry(name)) + { + // Module content URLs start with 0, whereas module + // class path URLs start with the index into the class + // path + 1. + url = getURLPolicy().createURL(0, name); + } + } + + return url; + } + + public boolean hasInputStream(int index, String urlPath) + { + if (urlPath.startsWith("/")) + { + urlPath = urlPath.substring(1); + } + if (index == 0) + { + return m_content.hasEntry(urlPath); + } + return m_contentPath[index - 1].hasEntry(urlPath); + } + + public InputStream getInputStream(int index, String urlPath) + throws IOException + { + if (urlPath.startsWith("/")) + { + urlPath = urlPath.substring(1); + } + if (index == 0) + { + return m_content.getEntryAsStream(urlPath); + } + return m_contentPath[index - 1].getEntryAsStream(urlPath); + } + + public String toString() + { + return m_searchPolicy.toString(); + } + + private void initializeContentPath() throws Exception + { + // Creating the content path entails examining the bundle's + // class path to determine whether the bundle JAR file itself + // is on the bundle's class path and then creating content + // objects for everything on the class path. + + // Get the bundle's manifest header. + InputStream is = null; + Map headers = null; + try + { + is = m_content.getEntryAsStream("META-INF/MANIFEST.MF"); + headers = new StringMap(new Manifest(is).getMainAttributes(), false); + } + finally + { + if (is != null) is.close(); + } + + // Find class path meta-data. + String classPath = (headers == null) + ? null : (String) headers.get(FelixConstants.BUNDLE_CLASSPATH); + + // Parse the class path into strings. + String[] classPathStrings = ManifestParser.parseDelimitedString( + classPath, FelixConstants.CLASS_PATH_SEPARATOR); + + if (classPathStrings == null) + { + classPathStrings = new String[0]; + } + + // Create the bundles class path. + List contentList = new ArrayList(); + for (int i = 0; i < classPathStrings.length; i++) + { + // Remove any leading slash, since all bundle class path + // entries are relative to the root of the bundle. + classPathStrings[i] = (classPathStrings[i].startsWith("/")) + ? classPathStrings[i].substring(1) + : classPathStrings[i]; + + // Check for the bundle itself on the class path. + if (classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT)) + { + contentList.add(m_content); + } + else + { + // Determine if the class path entry is a file or directory + // in the bundle JAR file. + IContent content = m_content.getEntryAsContent(classPathStrings[i]); + if (content != null) + { + contentList.add(content); + } + else + { +// TODO: FRAMEWORK - Per the spec, this should fire a FrameworkEvent.INFO event; +// need to create an "Eventer" class like "Logger" perhaps. + m_logger.log(Logger.LOG_INFO, + "Class path entry not found: " + + classPathStrings[i]); + } + } + } + + // If there is nothing on the class path, then include + // "." by default, as per the spec. + if (contentList.size() == 0) + { + contentList.add(m_content); + } + + m_contentPath = (IContent[]) contentList.toArray(new IContent[contentList.size()]); + } +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleDefinition.java URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleDefinition.java?rev=690991&view=auto ============================================================================== --- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleDefinition.java (added) +++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleDefinition.java Mon Sep 1 08:08:01 2008 @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.framework.searchpolicy; + +import org.apache.felix.framework.util.manifestparser.R4Library; +import org.apache.felix.moduleloader.*; + +public class ModuleDefinition implements IModuleDefinition +{ + public ICapability[] m_capabilities = null; + public IRequirement[] m_requirements = null; + public IRequirement[] m_dynamicRequirements = null; + private R4Library[] m_libraries = null; + + public ModuleDefinition( + ICapability[] capabilities, IRequirement[] requirements, + IRequirement[] dynamicRequirements, R4Library[] libraries) + { + m_capabilities = capabilities; + m_requirements = requirements; + m_dynamicRequirements = dynamicRequirements; + m_libraries = libraries; + } + + public ICapability[] getCapabilities() + { +// TODO: RB - These should probably all return copies of the array. + return m_capabilities; + } + + public IRequirement[] getRequirements() + { + return m_requirements; + } + + public IRequirement[] getDynamicRequirements() + { + return m_dynamicRequirements; + } + + // TODO: EXPERIMENTAL - Experimental implicit wire concept to try + // to deal with code generation. + public void setDynamicRequirements(IRequirement[] reqs) + { + m_dynamicRequirements = reqs; + } + + public R4Library[] getLibraries() + { + return m_libraries; + } +} \ No newline at end of file Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleDefinition.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleDefinition.java ------------------------------------------------------------------------------ svn:keywords = Rev Date