blob: 5d589bba408262c94c0eec8bc97cfdea5aa569fc [file] [log] [blame]
/*
* Copyright 2005 The Apache Software Foundation
*
* Licensed 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.osgi.framework;
import java.util.Map;
import org.apache.osgi.framework.cache.BundleArchive;
import org.apache.osgi.moduleloader.Module;
import org.osgi.framework.*;
class BundleInfo
{
private LogWrapper m_logger = null;
private BundleArchive m_archive = null;
private Module[] m_modules = null;
private int m_state = 0;
private BundleActivator m_activator = null;
private BundleContext m_context = null;
// Indicates that the bundle was either updated
// or uninstalled and is waiting to be removed or refreshed.
private boolean m_removalPending = false;
// Used for bundle locking.
private int m_lockCount = 0;
private Thread m_lockThread = null;
protected BundleInfo(LogWrapper logger, BundleArchive archive, Module module)
throws Exception
{
m_logger = logger;
m_archive = archive;
m_modules = (module == null) ? new Module[0] : new Module[] { module };
m_state = Bundle.INSTALLED;
m_removalPending = false;
m_activator = null;
m_context = null;
}
/**
* Returns the bundle archive associated with this bundle.
* @return the bundle archive associated with this bundle.
**/
public BundleArchive getArchive()
{
return m_archive;
}
/**
* Returns an array of all modules associated with the bundle represented by
* this <tt>BundleInfo</tt> object. A module in the array corresponds to a
* revision of the bundle's JAR file and is ordered from oldest to newest.
* Multiple revisions of a bundle JAR file might exist if a bundle is
* updated, without refreshing the framework. In this case, exports from
* the prior revisions of the bundle JAR file are still offered; the
* current revision will be bound to packages from the prior revision,
* unless the packages were not offered by the prior revision. There is
* no limit on the potential number of bundle JAR file revisions.
* @return array of modules corresponding to the bundle JAR file revisions.
**/
public Module[] getModules()
{
return m_modules;
}
/**
* Determines if the specified module is associated with this bundle.
* @param module the module to determine if it is associate with this bundle.
* @return <tt>true</tt> if the specified module is in the array of modules
* associated with this bundle, <tt>false</tt> otherwise.
**/
public boolean hasModule(Module module)
{
for (int i = 0; i < m_modules.length; i++)
{
if (m_modules[i] == module)
{
return true;
}
}
return false;
}
/**
* Returns the newest module, which corresponds to the last module
* in the module array.
* @return the newest module.
**/
public Module getCurrentModule()
{
return m_modules[m_modules.length - 1];
}
/**
* Add a module that corresponds to a new bundle JAR file revision for
* the bundle associated with this <tt>BundleInfo</tt> object.
* @param module the module to add.
**/
public void addModule(Module module)
{
Module[] dest = new Module[m_modules.length + 1];
System.arraycopy(m_modules, 0, dest, 0, m_modules.length);
dest[m_modules.length] = module;
m_modules = dest;
}
public long getBundleId()
{
return m_archive.getId();
}
public String getLocation()
{
try
{
return m_archive.getLocation();
}
catch (Exception ex)
{
m_logger.log(
LogWrapper.LOG_ERROR,
"Error reading location from bundle archive.",
ex);
return null;
}
}
public int getStartLevel(int defaultLevel)
{
try
{
return m_archive.getStartLevel();
}
catch (Exception ex)
{
m_logger.log(
LogWrapper.LOG_ERROR,
"Error reading start level from bundle archive.",
ex);
return defaultLevel;
}
}
public void setStartLevel(int i)
{
try
{
m_archive.setStartLevel(i);
}
catch (Exception ex)
{
m_logger.log(
LogWrapper.LOG_ERROR,
"Error writing start level to bundle archive.",
ex);
}
}
public Map getCurrentHeader()
{
try
{
// Return the header for the most recent bundle revision only,
// since we shouldn't ever need access to older revisions.
return m_archive.getManifestHeader(m_archive.getRevisionCount() - 1);
}
catch (Exception ex)
{
m_logger.log(
LogWrapper.LOG_ERROR,
"Error reading manifest from bundle archive.",
ex);
return null;
}
}
public int getState()
{
return m_state;
}
public void setState(int i)
{
m_state = i;
}
public int getPersistentState()
{
try
{
return m_archive.getPersistentState();
}
catch (Exception ex)
{
m_logger.log(
LogWrapper.LOG_ERROR,
"Error reading persistent state from bundle archive.",
ex);
return Bundle.INSTALLED;
}
}
public void setPersistentStateInactive()
{
try
{
m_archive.setPersistentState(Bundle.INSTALLED);
}
catch (Exception ex)
{
m_logger.log(LogWrapper.LOG_ERROR,
"Error writing persistent state to bundle archive.",
ex);
}
}
public void setPersistentStateActive()
{
try
{
m_archive.setPersistentState(Bundle.ACTIVE);
}
catch (Exception ex)
{
m_logger.log(
LogWrapper.LOG_ERROR,
"Error writing persistent state to bundle archive.",
ex);
}
}
public void setPersistentStateUninstalled()
{
try
{
m_archive.setPersistentState(Bundle.UNINSTALLED);
}
catch (Exception ex)
{
m_logger.log(
LogWrapper.LOG_ERROR,
"Error writing persistent state to bundle archive.",
ex);
}
}
public BundleContext getContext()
{
return m_context;
}
public void setContext(BundleContext context)
{
m_context = context;
}
public BundleActivator getActivator()
{
return m_activator;
}
public void setActivator(BundleActivator activator)
{
m_activator = activator;
}
public boolean isRemovalPending()
{
return m_removalPending;
}
public void setRemovalPending()
{
m_removalPending = true;
}
//
// Locking related methods.
// NOTE: These methods are not synchronized because it is assumed they
// will only ever be called when the caller is in a synchronized block.
//
public boolean isLockable()
{
return (m_lockCount == 0) || (m_lockThread == Thread.currentThread());
}
public void lock()
{
if ((m_lockCount > 0) && (m_lockThread != Thread.currentThread()))
{
throw new IllegalStateException("Bundle is locked by another thread.");
}
m_lockCount++;
m_lockThread = Thread.currentThread();
}
public void unlock()
{
if (m_lockCount == 0)
{
throw new IllegalStateException("Bundle is not locked.");
}
if ((m_lockCount > 0) && (m_lockThread != Thread.currentThread()))
{
throw new IllegalStateException("Bundle is locked by another thread.");
}
m_lockCount--;
if (m_lockCount == 0)
{
m_lockThread = null;
}
}
public void syncLock(BundleInfo info)
{
m_lockCount = info.m_lockCount;
m_lockThread = info.m_lockThread;
}
/**
* Converts a module identifier to a bundle identifier. Module IDs
* are typically <tt>&lt;bundle-id&gt;.&lt;revision&gt;</tt>; this
* method returns only the portion corresponding to the bundle ID.
**/
protected static long getBundleIdFromModuleId(String id)
{
try
{
String bundleId = (id.indexOf('.') >= 0)
? id.substring(0, id.indexOf('.')) : id;
return Long.parseLong(bundleId);
}
catch (NumberFormatException ex)
{
return -1;
}
}
/**
* Converts a module identifier to a bundle identifier. Module IDs
* are typically <tt>&lt;bundle-id&gt;.&lt;revision&gt;</tt>; this
* method returns only the portion corresponding to the revision.
**/
protected static int getModuleRevisionFromModuleId(String id)
{
try
{
String rev = (id.indexOf('.') >= 0)
? id.substring(id.indexOf('.') + 1) : id;
return Integer.parseInt(rev);
}
catch (NumberFormatException ex)
{
return -1;
}
}
}