diff options
19 files changed, 2488 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.frameworkadmin/.classpath b/bundles/org.eclipse.equinox.frameworkadmin/.classpath new file mode 100644 index 000000000..61c682532 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/.classpath @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="test"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/bundles/org.eclipse.equinox.frameworkadmin/.project b/bundles/org.eclipse.equinox.frameworkadmin/.project new file mode 100644 index 000000000..908721184 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.equinox.frameworkadmin</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/bundles/org.eclipse.equinox.frameworkadmin/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.frameworkadmin/META-INF/MANIFEST.MF new file mode 100644 index 000000000..478b0cf63 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: FrameworkAdmin Service IF +Bundle-SymbolicName: org.eclipse.equinox.frameworkadmin +Bundle-Version: 1.0.0 +Bundle-Vendor: Eclipse.org +Bundle-Localization: plugin +Import-Package: org.osgi.framework;version="1.3.0", + org.osgi.service.startlevel;version="1.0.0" +Export-Package: org.eclipse.equinox.configurator, + org.eclipse.equinox.frameworkadmin, + org.eclipse.equinox.internal.frameworkadmin.utils, + org.eclipse.equinox.internal.simpleconfigurator.utils diff --git a/bundles/org.eclipse.equinox.frameworkadmin/build.properties b/bundles/org.eclipse.equinox.frameworkadmin/build.properties new file mode 100644 index 000000000..34d2e4d2d --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/bundles/org.eclipse.equinox.frameworkadmin/doc/readme.txt b/bundles/org.eclipse.equinox.frameworkadmin/doc/readme.txt new file mode 100644 index 000000000..a153dfab1 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/doc/readme.txt @@ -0,0 +1,31 @@ +2006/12/18 + +This bundle contains API related with FwHandler. + +------------------------- +* Packages +- org.eclipse.core.fwhandler: contains APIs for handling framework (hereafter shortened as fw) + without Configurator. + +- org.eclipse.core.configurator: contains APIs related with configurator which configures bundle's lifecycle on a fw. + +- org.eclipse.core.fwhandler.configurator: contains APIs for handling fw with Configurator. + +------------------------- +* Developers are recommended to read the comments (or JavaDocs) in the following order. + +1. FwHandlerAdmin in org.eclipse.core.fwhandler. +2. Other APIs in org.eclipse.core.fwhandler. +3. Configurator in org.eclipse.core.configurator. +4. ConfiguratorManipilatorAdmin and ConfiguratorManipilator in org.eclipse.core.configurator. +5. APIs in org.eclipse.core.fwhandler.configurator + +------------------------- +* Other remarks + +Examples of implementation of FwHandlerAdmin are "org.eclipse.core.fwhandler.equinox" bundle + and "org.eclipse.core.fwhandler.kf" bundle. +An example of implementation of Configurator is "org.eclipse.core.simpleConfigurator" bundle. +An example of implementation of ConfiguratorManipulatorAdmin is "org.eclipse.core.fwhandler.simpleConfigurator.manipulator" bundle. + +An example using FwHandlerAdmin is "org.eclipse.core.fwhandler.examples" bundle. diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/configurator/Configurator.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/configurator/Configurator.java new file mode 100644 index 000000000..ff452a045 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/configurator/Configurator.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.configurator; + +import java.io.IOException; +import java.net.URL; + +import org.eclipse.equinox.frameworkadmin.BundleInfo; + +/** + * The implementation of this interface will be registered into a service registry + * by a Configurator Bundle. + * + * The client bundle can apply configuration which can be interpreted by refering + * the specified location to the current running OSGi environment. In addition, + * the client can expect bundle state in advance . + * + * TODO: this interface might not be required to be defined. + * + * + * ********************************************** + * Current Definition of Configurator Bundle: + * + * Configurator Bundle will do the followinig operation at its startup. + * + * 1. Create a Configurator object. + * 2. Register it as a service to the service registry. + * 3. Get where to read for knowing what kinds of bundles in its implementation dependend way. + * 4. Call {@link Configurator#applyConfiguration(URL)} with the URL. + * + * At its stopping, the service registered will be unregistered. + * + * @see ConfiguratorManipulator + * + */ +public interface Configurator { + + /** + * Apply configuration read from the specified url to the OSGi + * environment currently running. + * + * @param url URL to be read. + * @throws IOException - If reading information from the specified url fails. + */ + void applyConfiguration(URL url) throws IOException; + + + /** + * Return expected bundle states (as an array of BundleInfo) + * as if {@link Configurator#applyConfiguration(URL)} with an argument of the specified + * url will be called now. + * + * If there are no ManipulatorAdmin services which create a Manipulator initialized according to + * the running fw state, null will be returned. + * + * This method can be used to check what kinds of bundles will be + * installed on the system in advance to calling {@link Configurator#applyConfiguration(URL)}. + * + * @param url URL to be referred. + * @return Array of BundleInfo representing the expected state. null + * if there are no ManipulatorAdmin services which create a Manipulator initialized according to + * the running fw state. + * @throws IOException - If reading information from the specified url fails. + */ + BundleInfo[] getExpectedStateRuntime(URL url) throws IOException; +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/configurator/ConfiguratorManipulator.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/configurator/ConfiguratorManipulator.java new file mode 100644 index 000000000..358b2afc0 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/configurator/ConfiguratorManipulator.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.configurator; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.equinox.frameworkadmin.*; + +/** + * + * This interface provides methods that enable client bundles to + * manipulate the corresponding ConfiguratorBundle. + * + * @see Configurator + */ + +public interface ConfiguratorManipulator { + String SERVICE_PROP_KEY_CONFIGURATOR_BUNDLESYMBOLICNAME = "org.eclipse.equinox.configurator.BundleSymbolicName"; + + /** + * Save configuration for the corresponding Configurator Bundle so that + * Bundles kept by the specified {@link Manipulator} would be installed after completion of a launch. + * The location of a configuration file is determined by the parameters set to the Manipulator object + * and it depends on the corresponding ConfiguratorBundle implementation. + * + * While some parameters of the {@link Manipulator} object will be modified (for setting info about the + * location the ConfiguratorBundle would be able to refer in a future launch), + * the Bundles kept by the {@link Manipulator} object should not be modified. + * + * Instead, it will return BundleInfo[] to be managed not by the ConfiguratorBundle. + * These values are supposed to be saved into fw config files. + * + * If backup flag is true, a file have existed already under the same name + * will be renamed into another name as a backup. + * + * We assume that the implementation of {@link Manipulator#save(boolean)} will call this method. + * + * @return array of BundleInfo to be saved as installing bundles in fw config files. + * @param Manipulator {@link Manipulator} object which contains the bundles to be installed finally. + * @param backup if files exists at the location to save, it will be copied as a backup. + * @throws IOException - If fail to save configuration for the corresponding Configurator Bundle. + */ + BundleInfo[] save(Manipulator Manipulator, boolean backup) throws IOException; + + /** + * Update bundles kept by the specified {@link Manipulator} object into installed bundles + * if {@link FrameworkAdmin#launch(Manipulator, File)} with the specified + * {@link Manipulator} is called taking the corresponding ConfiguratorBundle behaivior into account. + * + * If there is no corresponding ConfiguratorBundle in Manipulator.getConfigData().getBundles(), + * just return. + * + * The BundleInfo[] of the specified Manipulator object will be modified. + * + * This method is assumed to be called from {@link Manipulator#load()}. + * + * @param Manipulator {@link Manipulator} object to be used and updated. + * @throws IOException - If fail to read configuration for the corresponding Configurator Bundle. + */ + void updateBundles(Manipulator Manipulator) throws IOException; + +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/BundleInfo.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/BundleInfo.java new file mode 100644 index 000000000..363b31847 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/BundleInfo.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.frameworkadmin; + +/** + * This object represents information of a bundle. + * + */ +public class BundleInfo { + public static final int NO_LEVEL = -1; + + private String symbolicName = null; + private String version = null; + private String location; + private boolean markedAsStarted = false; + private int startLevel = NO_LEVEL; + private boolean resolved = false; + + // private Dictionary manifest; + + public BundleInfo() { + } + + public BundleInfo(String location) { + this.location = location.trim(); + } + + public BundleInfo(String location, boolean started) { + this.location = location.trim(); + this.markedAsStarted = started; + } + + public BundleInfo(String location, int startLevel) { + this.location = location.trim(); + this.startLevel = startLevel; + } + + public BundleInfo(String location, int startLevel, boolean started) { + this.location = location.trim(); + this.startLevel = startLevel; + this.markedAsStarted = started; + } + + public BundleInfo(String symbolic, String version, String location, int startLevel, boolean started) { + this.symbolicName = symbolic; + this.version = version; + this.location = location.trim(); + this.markedAsStarted = started; + this.startLevel = startLevel; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object toCompare) { + if (toCompare instanceof BundleInfo) { + BundleInfo info = (BundleInfo) toCompare; + //if (info.symbolicName.equals(symbolicName) && info.version.equals(version) && (info.url == null || url == null ? true : info.url.equals(url))) + if (info.symbolicName != null && info.version != null && symbolicName != null && version != null) { + if (info.symbolicName.equals(symbolicName) && info.version.equals(version) && (info.location == null || location == null ? true : info.location.equals(location))) + return true; + } else { + return (info.location == null || location == null ? false : info.location.equals(location)); + } + } + return false; + } + + public String getLocation() { + return location; + } + + public int getStartLevel() { + return startLevel; + } + + public String getSymbolicName() { + return symbolicName; + } + + public String getVersion() { + return version; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + int result = symbolicName == null ? 0 : symbolicName.hashCode(); + result = result + (version == null ? 0 : version.hashCode()); + result = result + (location == null ? 0 : location.hashCode()); + return result; + } + + public boolean isMarkedAsStarted() { + return markedAsStarted; + } + + public boolean isResolved() { + return resolved; + } + + public void setLocation(String location) { + this.location = location.trim(); + } + + public void setMarkedAsStarted(boolean markedAsStarted) { + this.markedAsStarted = markedAsStarted; + } + + public void setResolved(boolean resolved) { + this.resolved = resolved; + } + + public void setStartLevel(int level) { + this.startLevel = level; + } + + public void setSymbolicName(String symbolicName) { + this.symbolicName = symbolicName; + } + + public void setVersion(String vertion) { + this.version = vertion; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("BundleInfo("); //$NON-NLS-1$ + if (symbolicName != null) + buffer.append(symbolicName); + buffer.append(", "); + if (version != null) + buffer.append(version); + buffer.append(", "); + buffer.append("location="); + buffer.append(location); + buffer.append(", startLevel="); //$NON-NLS-1$ + buffer.append(startLevel); + buffer.append(", toBeStarted="); + buffer.append(markedAsStarted); + buffer.append(", resolved="); + buffer.append(resolved); + // buffer.append(',').append(manifest == null ? "no manifest" : "manifest available"); + buffer.append(')'); + return buffer.toString(); + } +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/BundlesState.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/BundlesState.java new file mode 100644 index 000000000..c72c116d0 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/BundlesState.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.frameworkadmin; + +/** + * This API is used for expecting bundles state virtually. + * + * This object is instantiated by {@link Manipulator#getBundlesState()}. + * At its instantiation, state of the bundles will be created in this object + * according to the parameters which the calling {@link Manipulator} object has. + * For its creation, information in the fw persistent data will be taken into account. + * + * Modification of this object after its instantiation never affects the parameters + * in the calling {@link Manipulator} object. + * + * XXX Implementation of Simple ConfiguratorManipulator needs the functions. + * + * @see Manipulator + */ +public interface BundlesState { + + /** Return expected bundles state currently kept in this object. + * + * The implementation of this method will try to resolve the state + * if resolving a state is supported. + * + * @return bundle array of BundleInfo currently composed in this object. + * @throws FrameworkAdminRuntimeException - If the {@link FrameworkAdmin} service created the parent {@link Manipulator} is unregistered. + */ + BundleInfo[] getExpectedState() throws FrameworkAdminRuntimeException; + + /** + * Return required bundles to be resolve the specified bInfo + * under the state currently composed. + * + * The implementation of this method will try to resolve the state + * if resolving a state is supported. + * + * @param bInfo bundleinfo whose prerequisite bundles will be searched. + * @return bundle array of BundleInfos required for the specified bInfo to be resolved. + */ + BundleInfo[] getPrerequisteBundles(BundleInfo bInfo); + + /** + * Return a bundle to be used as a framework under the state currently composed. + * @return a bundle to be used as a framework under the state currently composed. + */ + public BundleInfo getSystemBundle(); + + /** + * Return bundles which are fragment bundles of the framework under the state currently composed. + * @return array of BundleInfos which are fragment bundles of the framework. + */ + public BundleInfo[] getSystemFragmentedBundles(); + + /** + * Return array of Strings which tells the unsatisfied constaints + * to resolve the specified bInfo under the state currently composed. + * + * If this implementation doesn't support resolving state, + * FrameworkAdminRuntimeException with a cause of {@value FrameworkAdminRuntimeException#UNSUPPORTED_OPERATION} + * will be thrown. + * + * XXX this method is prepared mainly for debugging. + * + * @param bInfo + * @return array of Strings which tells the unsatisfied constaints. + * @throws FrameworkAdminRuntimeException if this implementation doesn't support resolving state, FrameworkAdminRuntimeException with a cause of {@value FrameworkAdminRuntimeException#UNSUPPORTED_OPERATION} will be thrown. + */ + public String[] getUnsatisfiedConstraints(BundleInfo bInfo) throws FrameworkAdminRuntimeException; + + /** + * Install the specified bInfo as a installed bundle to the current state virtually. + * Note that resolve this bundle is not done in this implementation. + * + * @param bInfo BundleInfo to be installed + * @throws FrameworkAdminRuntimeException - If the {@link FrameworkAdmin} service created the parent {@link Manipulator} is unregistered. + */ + void installBundle(BundleInfo bInfo) throws FrameworkAdminRuntimeException; + + /** + * Return true if this implementation supports full functions, + * such as resolving bundles and . + * Otherwise false will be returend. + * @return true if this implementation supports resolving state. Otherwise false. + */ + boolean isFullySupported(); + + /** + * Return true if the state currently composed is resolved after the last change of the state. + * Otherwise false. + * + * If this implementation doesn't support resolving state, + * FrameworkAdminRuntimeException with a cause of {@value FrameworkAdminRuntimeException#UNSUPPORTED_OPERATION} + * will be thrown. + * + * @return true if the state currently composed is resolved after the last change of the state. Otherwise false. + * @throws FrameworkAdminRuntimeException if this implementation doesn't support resolving state, FrameworkAdminRuntimeException with a cause of {@value FrameworkAdminRuntimeException#UNSUPPORTED_OPERATION} will be thrown. + */ + public boolean isResolved() throws FrameworkAdminRuntimeException; + + /** + * Return true if the specified bundle is resolved. + * Otherwise false. + * + * If this implementation doesn't support resolving state, + * FwLauncherException with a cause of {@value FwLauncherException#UNSUPPORTED_OPERATION} + * will be thrown. + * + * @return true if the specified bundle is resolved. Otherwise false. + * @throws FrameworkAdminRuntimeException if this implementation doesn't support resolving state, FrameworkAdminRuntimeException with a cause of {@value FrameworkAdminRuntimeException#UNSUPPORTED_OPERATION} will be thrown. + */ + public boolean isResolved(BundleInfo bInfo) throws FrameworkAdminRuntimeException; + + /** + * Resolves the constraints contained in this state. + * + * If this implementation doesn't support resolving state, + * FrameworkAdminRuntimeException with a cause of {@value FrameworkAdminRuntimeException#UNSUPPORTED_OPERATION} + * will be thrown. + * + * @param incremental a flag controlling whether resolution should be incremental + * @throws FrameworkAdminRuntimeException + */ + void resolve(boolean increment) throws FrameworkAdminRuntimeException; + + /** + * Uninstall the specified bInfo from the current state virtually. + * + * @param bInfo BundleInfo to be uninstalled + * @throws FrameworkAdminRuntimeException - If the {@link FrameworkAdmin} service created the parent {@link Manipulator} is unregistered. + */ + void uninstallBundle(BundleInfo bInfo) throws FrameworkAdminRuntimeException;; +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/ConfigData.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/ConfigData.java new file mode 100644 index 000000000..15165371c --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/ConfigData.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.equinox.frameworkadmin; + +import java.util.*; + +/** + * This object is instantiated by {@link Manipulator#getConfigData()}; + * The class that keeps some parameters of the {@link Manipulator} + * created this object. The manipulating of the parameters will affect + * the {@link Manipulator}. + * + * @see Manipulator + */ +public class ConfigData { + + private static Properties appendProperties(Properties to, Properties from) { + if (from != null) { + if (to == null) + to = new Properties(); + // printoutProperties(System.out, "to", to); + // printoutProperties(System.out, "from", from); + + for (Enumeration enumeration = from.keys(); enumeration.hasMoreElements();) { + String key = (String) enumeration.nextElement(); + to.setProperty(key, from.getProperty(key)); + } + } + // printoutProperties(System.out, "to", to); + return to; + } + + final private String fwName; + final private String fwVersion; + final private String launcherName; + final private String launcherVersion; + private int beginningFwStartLevel = BundleInfo.NO_LEVEL; + private int initialBundleStartLevel = BundleInfo.NO_LEVEL; + // List of BundleInfo + private List bundlesList = new LinkedList(); + private Properties fwIndependentProps = new Properties(); + + private Properties fwDependentProps = new Properties(); + + public ConfigData(String fwName, String fwVersion, String launcherName, String launcherVersion) { + this.fwName = fwName; + this.fwVersion = fwVersion; + this.launcherName = launcherName; + this.launcherVersion = launcherVersion; + this.initialize(); + } + + public void addBundle(BundleInfo bundleInfo) { + this.bundlesList.add(bundleInfo); + } + + public int getBeginingFwStartLevel() { + return this.beginningFwStartLevel; + } + + public BundleInfo[] getBundles() { + if (bundlesList.size() == 0) + return new BundleInfo[0]; + BundleInfo[] ret = new BundleInfo[bundlesList.size()]; + bundlesList.toArray(ret); + return ret; + } + + public String getFwDependentProp(String key) { + return fwDependentProps.getProperty(key); + } + + public Properties getFwDependentProps() { + Properties ret = new Properties(); + appendProperties(ret, fwDependentProps); + return ret; + } + + public String getFwIndependentProp(String key) { + return fwIndependentProps.getProperty(key); + } + + public Properties getFwIndependentProps() { + Properties ret = new Properties(); + appendProperties(ret, fwIndependentProps); + return ret; + } + + public String getFwName() { + return this.fwName; + } + + public String getFwVersion() { + return this.fwVersion; + } + + public int getInitialBundleStartLevel() { + return this.initialBundleStartLevel; + } + + public String getLauncherName() { + return launcherName; + } + + public String getLauncherVersion() { + return launcherVersion; + } + + public void initialize() { + this.beginningFwStartLevel = BundleInfo.NO_LEVEL; + this.initialBundleStartLevel = BundleInfo.NO_LEVEL; + this.bundlesList.clear(); + this.fwIndependentProps.clear(); + this.fwDependentProps.clear(); + } + + public void removeBundle(BundleInfo bundleInfo) { + this.bundlesList.remove(bundleInfo); + } + + public void setBeginningFwStartLevel(int startLevel) { + this.beginningFwStartLevel = startLevel; + } + + public void setBundles(BundleInfo[] bundleInfos) { + this.bundlesList.clear(); + if (bundleInfos != null) + for (int i = 0; i < bundleInfos.length; i++) + bundlesList.add(bundleInfos[i]); + } + + public void setFwDependentProp(String key, String value) { + this.fwDependentProps.setProperty(key, value); + } + + public void setFwDependentProps(Properties props) { + this.fwDependentProps.clear(); + appendProperties(fwDependentProps, props); + } + + public void setFwIndependentProp(String key, String value) { + this.fwIndependentProps.setProperty(key, value); + } + + public void setFwIndependentProps(Properties props) { + this.fwIndependentProps.clear(); + appendProperties(fwIndependentProps, props); + } + + public void setInitialBundleStartLevel(int startLevel) { + this.initialBundleStartLevel = startLevel; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("Class:" + this.getClass().getName() + "\n"); + sb.append("============Independent===============\n"); + sb.append("fwName=" + this.fwName + "\n"); + sb.append("fwVersion=" + this.fwVersion + "\n"); + sb.append("launcherName=" + this.launcherName + "\n"); + sb.append("launcherVersion=" + this.launcherVersion + "\n"); + sb.append("beginningFwStartLevel=" + this.beginningFwStartLevel + "\n"); + sb.append("initialBundleStartLevel=" + this.initialBundleStartLevel + "\n"); + if (this.bundlesList.size() == 0) + sb.append("bundlesList=null\n"); + else { + sb.append("bundlesList=\n"); + for (int i = 0; i < this.bundlesList.size(); i++) + sb.append("\tbundlesList[" + i + "]=" + bundlesList.get(i).toString() + "\n"); + } + + sb.append("============ Fw Independent Props ===============\n"); + sb.append("fwIndependentProps="); + if (fwIndependentProps.size() > 0) + sb.append("\n" + fwIndependentProps.toString() + "\n"); + else + sb.append("null\n"); + sb.append("============ Fw Dependent Props ===============\n"); + sb.append("fwDependentProps="); + if (fwDependentProps.size() > 0) + sb.append("\n" + fwDependentProps.toString() + "\n"); + else + sb.append("null\n"); + + return sb.toString(); + } + +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/FrameworkAdmin.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/FrameworkAdmin.java new file mode 100644 index 000000000..25b03a5ef --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/FrameworkAdmin.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.frameworkadmin; + +import java.io.File; +import java.io.IOException; + +/** + * The implementation of this API will be registered to the service + * registry as an OSGi service. + * + * ***************************************************************** + * 1. For developers who implement bundles that register this service. + * + * At the registration, the following + * service properties must be set for client to search the FrameworkAdmin object + * which will create BundlesState / ConfigData / LauncherData objects. + * + * {@link FrameworkAdmin#SERVICE_PROP_KEY_FW_NAME}: String; name of the framework + * {@link FrameworkAdmin#SERVICE_PROP_KEY_FW_VERSION}: String; version of the framework + * {@link FrameworkAdmin#SERVICE_PROP_KEY_LAUNCHER_NAME}: String; name of the launcher + * {@link FrameworkAdmin#SERVICE_PROP_KEY_LAUNCHER_VERSION}: String; version of the launcher + * + * Bundles register this service will check if the currently runnning system can be manipulated by + * this FrameworkAdmin. If yes and this implementation can create an initialized Manipulator object + * according to the running fw and launcher, add the service property keyed by + * + * {@link FrameworkAdmin#SERVICE_PROP_KEY_RUNNING_SYSTEM_FLAG}: String; if "true", this service that will be returned by getRunningManipulator() is fully initialized so as to represent the state of running system. + * + * It is recommended to implement Manipulator objects created by calling methods of this interface + * so that they cannot be used after this service is unregistered. + * + * ***************************************************************** + * 2. For developers who implement client bundles that use this service. + * + * A client bundle of this service can get new Manipulator object + * by calling its method. + * + * A client bundle can search among services registered in a service registry + * and can get the desired FrameworkAdmin service object so that the bundle + * can get the desired {@link Manipulator} object for desired framework type with version and launcher type with version. + * + * Especially, in order for a client bundle to manipulate the {@link Manipulator} object of the running fw and laucher, + * filtering (FrameworkAdmin#SERVICE_PROP_KEY_RUNNING_FW_FLAG=true) is used. + * + * As generally speaking about OSGi service, the client bundle should track this service state. + * If unregistered, it should stop using any of objects that it got by this service and + * release all of them. If it continues to use them, {@link FrameworkAdminRuntimeException} might + * be thrown. + * + */ +public interface FrameworkAdmin { + + String SERVICE_PROP_KEY_FW_NAME = "org.eclipse.equinox.frameworkhandler.framework.name"; + String SERVICE_PROP_KEY_FW_VERSION = "org.eclipse.equinox.frameworkhandler.framework.version"; + + String SERVICE_PROP_KEY_LAUNCHER_NAME = "org.eclipse.equinox.frameworkhandler.launcher.name"; + String SERVICE_PROP_KEY_LAUNCHER_VERSION = "org.eclipse.equinox.frameworkhandler.launcher.version"; + String SERVICE_PROP_KEY_RUNNING_SYSTEM_FLAG = "org.eclipse.equinox.frameworkhandler.runningfwflag"; + + /** + * Create new instance of {@link Manipulator} and return it. + * + * @return new instance of Manipulator. + */ + Manipulator getManipulator(); + + /** + * Create new instance of {@link Manipulator} for running system + * and return it. The instance must be initialized fully according to the + * running environment. If this implementation cannot provide it, return null. + * + * @return new instance of Manipulator. + */ + Manipulator getRunningManipulator(); + + /** + * Launch a framework instance under the specified current working directory. + * + * + * @param manipulator {@link Manipulator} object to be launched. + * @param cwd current working directory to be used for launching. + * @return process + * @throws IllegalArgumentException if specified arguments are null. + * @throws IOException if any error relate with IO occurs + * @throws FrameworkAdminRuntimeException if the FrameworkAdmin service object + * that created the specified Manipulator object is unregistered. + */ + Process launch(Manipulator manipulator, File cwd) throws IllegalArgumentException, IOException, FrameworkAdminRuntimeException; + + /** + * + * @return true if this object is active. false otherwise. + */ + boolean isActive(); +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/FrameworkAdminRuntimeException.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/FrameworkAdminRuntimeException.java new file mode 100644 index 000000000..7a0ae863c --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/FrameworkAdminRuntimeException.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.equinox.frameworkadmin; + +public class FrameworkAdminRuntimeException extends RuntimeException { + + private static final long serialVersionUID = -2292498677000772317L; + public static final String FRAMEWORKADMIN_UNAVAILABLE = "FrameworkAdmin service created this object is not available any more"; + public static final String UNSUPPORTED_OPERATION = "This implementation doesn't support this method."; + + private final String reason; + + /** + * @param message + */ + public FrameworkAdminRuntimeException(String message, String reason) { + super(message); + this.reason = reason; + } + + /** + * @param message + * @param cause + */ + public FrameworkAdminRuntimeException(String message, Throwable cause, String reason) { + super(message, cause); + this.reason = reason; + } + + /** + * @param cause + */ + public FrameworkAdminRuntimeException(Throwable cause, String reason) { + super(cause); + this.reason = reason; + } + + public String getReason() { + return reason; + } + +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/LauncherData.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/LauncherData.java new file mode 100644 index 000000000..92f15fcdf --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/LauncherData.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.frameworkadmin; + +import java.io.File; + +/** + * This object is instantiated by {@link Manipulator#getLauncherData()}; + * The class that keeps some parameters of the {@link Manipulator} + * created this object. The manipulating of the parameters will affect + * the {@link Manipulator}. + * + * + * @see Manipulator + */ +public class LauncherData { + private static final String[] NULL_STRINGS = new String[0]; + private File fwPersistentDataLocation = null; + private File jvm = null; + private String[] jvmArgs; + private boolean clean; + private File fwConfigLocation; + private File homeLocation = null; + private File fwJar = null; + + private File launcher = null; + private File launcherConfigLocation = null; + + private String fwName; + private String fwVersion; + private String launcherName; + private String launcherVersion; + + public LauncherData(String fwName, String fwVersion, String launcherName, String launcherVersion) { + this.fwName = fwName; + this.fwVersion = fwVersion; + this.launcherName = launcherName; + this.launcherVersion = launcherVersion; + this.initialize(); + } + + public void addJvmArgs(String[] args) { + if (args == null) { + jvmArgs = NULL_STRINGS; + return; + } + if (jvmArgs.length == 0) + this.setJvmArgs(args); + String[] newArgs = new String[jvmArgs.length + args.length]; + System.arraycopy(jvmArgs, 0, newArgs, 0, jvmArgs.length); + System.arraycopy(args, 0, newArgs, jvmArgs.length, args.length); + jvmArgs = newArgs; + } + + public File getFwConfigLocation() { + return fwConfigLocation; + } + + public File getFwJar() { + return fwJar; + } + + public String getFwName() { + return fwName; + } + + public File getFwPersistentDataLocation() { + return fwPersistentDataLocation; + } + + public String getFwVersion() { + return fwVersion; + } + + public File getHome() { + return homeLocation; + } + + public File getJvm() { + return jvm; + } + + public String[] getJvmArgs() { + return jvmArgs; + } + + public File getLauncher() { + return launcher; + } + + public File getLauncherConfigLocation() { + return launcherConfigLocation; + } + + public String getLauncherName() { + return launcherName; + } + + public String getLauncherVersion() { + return launcherVersion; + } + + public void initialize() { + fwPersistentDataLocation = null; + jvm = null; + jvmArgs = NULL_STRINGS; + clean = false; + fwConfigLocation = null; + fwJar = null; + launcher = null; + } + + public boolean isClean() { + return clean; + } + + public void setFwConfigLocation(File fwConfigLocation) { + this.fwConfigLocation = fwConfigLocation; + } + + public void setFwJar(File fwJar) { + this.fwJar = fwJar; + } + + public void setFwPersistentDataLocation(File fwPersistentDataLocation, boolean clean) { + this.fwPersistentDataLocation = fwPersistentDataLocation; + this.clean = clean; + } + + public void setHomeLocation(File homeLocation) { + this.homeLocation = homeLocation; + } + + public void setJvm(File file) { + this.jvm = file; + } + + public void setJvmArgs(String[] args) { + if (args == null) { + jvmArgs = NULL_STRINGS; + return; + } + String[] jvmArgs = new String[args.length]; + System.arraycopy(args, 0, jvmArgs, 0, args.length); + } + + public void setLauncher(File launcherFile) { + launcher = launcherFile; + } + + public void setLauncherConfigLocation(File launcherConfigLocation) { + this.launcherConfigLocation = launcherConfigLocation; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("Class:" + this.getClass().getName() + "\n"); + sb.append("fwName=" + this.fwName + "\n"); + sb.append("fwVersion=" + this.fwVersion + "\n"); + sb.append("launcherName=" + this.launcherName + "\n"); + sb.append("launcherVersion=" + this.launcherVersion + "\n"); + + sb.append("jvm=" + this.jvm + "\n"); + if (this.jvmArgs.length == 0) + sb.append("jvmArgs = null\n"); + else { + sb.append("jvmArgs=\n"); + for (int i = 0; i < this.jvmArgs.length; i++) + sb.append("\tjvmArgs[" + i + "]=" + jvmArgs[i] + "\n"); + } + + sb.append("fwConfigLocation=" + this.fwConfigLocation + "\n"); + sb.append("fwJar=" + this.fwJar + "\n"); + sb.append("fwPersistentDataLocation=" + this.fwPersistentDataLocation + "\n"); + sb.append("homeLocation=" + this.homeLocation + "\n"); + sb.append("launcher=" + this.launcher + "\n"); + sb.append("launcherConfigLocation=" + this.launcherConfigLocation + "\n"); + sb.append("clean=" + this.isClean() + "\n"); + + return sb.toString(); + } +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/Manipulator.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/Manipulator.java new file mode 100644 index 000000000..bdc120056 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/frameworkadmin/Manipulator.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.frameworkadmin; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.equinox.configurator.ConfiguratorManipulator; + +/** + * An object implementing this interface will be gotten by calling + * {@link FrameworkAdmin#getManipulator()}. + * + * The object plays main roles for handling a framwork, such as configuring a framework + * and launching. + * + * The typical usecases of this method: + * + * Usecase 1: set parameters, check the expected state, save them into configuration files, and launch. + * A. create a {@link Manipulator} object from a {@link FrameworkAdmin}. + * B. set parameters to the {@link Manipulator} object. + * C. getExpectedState() and check what bundle state will be realized. + * If it is not same as you desire, repeat B and C until it becomes as you desire. + * D. save parameters into configuration files by {@link Manipulator#save(boolean)}. + * E. launch the framework by {@link FrameworkAdmin#launch(Manipulator, File)}. + * + * Usecase 2: set parameters required for loading, load parameters from configuration files, + * check the expected state, and launch. + * A. create a {@link Manipulator} object from a {@link FrameworkAdmin}. + * B. set parameters about launcher or fw config file to the {@link Manipulator} object. + * C. load parameters from configuration files by {@link Manipulator#load()}; + * D. getExpectedState() and check what bundle state will be realized. + * E. launch the framework by {@link FrameworkAdmin#launch(Manipulator, File)}. + * @see FrameworkAdmin + * @see ConfigData + * @see LauncherData + */ + +public interface Manipulator { + + /** + * Return the newly created BundldsState object, + * according to the parameters set to this object "in memory". + * + * None of launcher config file, framework config file and configurator config file + * will be read by this method. However, the fw persistent data location should be + * taken into consideration. In other words, this method will return + * the expected {@link BundlesState} object assuming that the current parameters were saved and + * {@link FrameworkAdmin#launch(Manipulator, File)} with an argument of this object + * were called. (It would read the fw persistent data location if required). + * + * This method should not modify the parameters in this {@link Manipulator} object. + * + * @return fw bundle state object created according to he current parameters set. + * @throws FrameworkAdminRuntimeException - If the {@link FrameworkAdmin} service created this object is unregistered or this implementation doesn't support this method. + */ + BundlesState getBundlesState() throws FrameworkAdminRuntimeException; + + /** + * The reference of {@link ConfigData} object representing configuration information related with framework settings will be returned. + * Remind that manipulating returned object will affect this Manipulator behaivior. + * + * @return ConfigData object representing configuration information related with framework setting + * @throws FrameworkAdminRuntimeException - If the {@link FrameworkAdmin} service created this object is unregistered or this implementation doesn't support this method. + * @see ConfigData + */ + ConfigData getConfigData() throws FrameworkAdminRuntimeException; + + /** + * Return the expected BundldInfo array representing state of bundles, + * according to the parameters set to this object "in memory". + * + * None of launcher config file, framework config file and configurator config file + * will be read by this method. However, the fw persistent data location should be + * taken into consideration. In other words, this method will return + * the expected bundles state assuming that the current parameters were saved and + * {@link FrameworkAdmin#launch(Manipulator, File)} with an argument of this object + * were called. (It would read the fw persistent data location if required). + * + * Returned BundleInfos must have resolved flag set. + * This method should not modify the parameters in this {@link Manipulator} object. + * + * cf. getConfigData().getBundles() will return array of BundleInfo too. + * However the resolved flag of returned BundleInfos might not be reliable. + * + * This method is equivalent to calling getBundlesState().getExpectedState(). + * + * @return array of BundleInfo representing expected state of all bundles installed. + * @throws IllegalArgumentException - If either of fwJar or cwd doesn't exist. + * @throws IOException - If reading fw configuration file or reading persitently recorded information + * of fw fails. + * @throws FrameworkAdminRuntimeException - If the {@link FrameworkAdmin} service created this object is unregistered or this implementation doesn't support this method. + */ + BundleInfo[] getExpectedState() throws IllegalStateException, IOException, FrameworkAdminRuntimeException; + + /** + * The reference of {@link LauncherData} object representing configuration information + * related with launcher settings will be returned. + * Remember that manipulating returned object will affect this Manipulator object behaivior. + * + * @return LauncherData object representing configuration information related with launcher setting + * @throws FrameworkAdminRuntimeException - If the ManipulatorAdmin service created this object is unregistered or this implementation doesn't support this method. + * @see LauncherData + */ + LauncherData getLauncherData() throws FrameworkAdminRuntimeException; + + /** + * Initialize all information that this object keeps at that time. + */ + void initialize(); + + /** + * load configs from appropriate config files, + * including launcher config file, fw config file, and configurator config files, + * whose locations are determined by the current setting. In addition, + * the fw persistent data location should be taken into consideration. + * + * The following procedure contains the matters of implementation detail. + * However, it is an example how it works. + * + * 1. if launcher object is set, corresponding launcher config file will be read. + * According to the information retrieved, setting of this object will be updated. + * including fw config file. + * + * 2. If fw config file is not specified, IllegalStateException will be thrown. + * Otherwise, the information will be retrieved from the fw config file. + * + * 3. If any ConfiguratorBundle is included in the bundle list, + * read appropriate configurator config file by + * {@link ConfiguratorManipulator#updateBundles(Manipulator)}, + * which will update the parameter about installed bundles in its + * {@link Manipulator#getConfigData()} object. + * + * Most old parameters will be updated by this method call. + * + * @throws IOException - If reading info from configuration files fails. + * @throws IllegalStateException - If config files cannot be determined. + * @throws FrameworkAdminRuntimeException - If the {@link FrameworkAdmin} service created this object is unregistered or this implementation doesn't support this method. + */ + void load() throws IllegalStateException, IOException, FrameworkAdminRuntimeException; + + /** + * Save parameters that this object keeps at that time into appropriate config files, + * which include launcher config file, fw config file, and configurator config files + * (if required and implementation of this object supports), according to the current setting and situation. + * + * The followins procedure contains the matters of implementation detail. + * However, it is an example how it works. + * + * 1. if a launcher file is set, + * the parameters to be saved into a LauncherConfigFile will be saved into the default LauncherConfigFile + * that is determined by the location of the launcher file. + * + * + * 2. if there are any {@link ConfiguratorManipulator} objects available whose corresponding ConfiguratorBundle + * is set to be started, choose the ConfiguratorBudnle that starts the first among them and go to next step. + * Otherwise, save the BundleInfo[] set to this object into a FwConfigFile that is determined + * by the parameters set. + * + * 3. call {@link ConfiguratorManipulator#save(Manipulator, boolean)} of + * the ConfiguratorManipulator that can manipulate the chosen ConfiguratorBudnle. + * This method will save configs for ConfiguratorBundle to read appropriately + * and return BundleInfo[] to be saved in the FwConfigFile, which is determined by the parameters set. + * + * 4. Save the rerurned BundleInfo[] in the FwConfigFile, which is determined by the parameters set. + * + * @param backup - if true, keep old file by renaming if exists. + * @throws IOException - If writing info into configuration files fails. + * @throws FrameworkAdminRuntimeException - If the {@link FrameworkAdmin} service created this object is unregistered or this implementation doesn't support this method. + */ + void save(boolean backup) throws IOException, FrameworkAdminRuntimeException; + + /** + * Copy all information the specified {@link ConfigData} contains into this object. + * All of old settings will be initialized and replaced. + * + * @param configData fw config data to be set to this object. + */ + void setConfigData(ConfigData configData); + + /** + * Copy all information the specified {@link LauncherData} contains into this object. + * All of old settings will be initialized and replaced. + * + * @param launcherData launcher config data to be set to this object. + */ + void setLauncherData(LauncherData launcherData); +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/frameworkadmin/utils/SimpleBundlesState.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/frameworkadmin/utils/SimpleBundlesState.java new file mode 100644 index 000000000..b97007808 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/frameworkadmin/utils/SimpleBundlesState.java @@ -0,0 +1,338 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.frameworkadmin.utils; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.*; + +import org.eclipse.equinox.frameworkadmin.*; + +import org.eclipse.equinox.internal.frameworkadmin.utils.Utils; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; + +/** + * This implementation of BundlesState doesn't support any of + * - resolving bundles, + * - retrieving fw persistent data. + * + * This implementation can be used for those cases. + * + */ +/** + * @author iyamasak + * + */ +public class SimpleBundlesState implements BundlesState { + public static final BundleInfo[] NULL_BUNDLEINFOS = new BundleInfo[0]; + /** + * Check if the specified FrameworkAdmin is available. + * + * @param fwAdmin + * @throws FrameworkAdminRuntimeException + */ + public static void checkAvailability(FrameworkAdmin fwAdmin) throws FrameworkAdminRuntimeException { + if (!fwAdmin.isActive()) + throw new FrameworkAdminRuntimeException("FrameworkAdmin creates this object is no more available.", FrameworkAdminRuntimeException.FRAMEWORKADMIN_UNAVAILABLE); + } + /** + * + * @param launcherData + * @return File of fwJar to be used. + * @throws IOException + */ + static File getFwJar(LauncherData launcherData) { + if (launcherData.getFwJar() != null) + return launcherData.getFwJar(); + return null; + } + private final String systemBundleSymbolicName; + + private final String systemBundleName; + + private final String systemBundleVendor; + BundleContext context = null; + List bundleInfosList = new LinkedList(); + + FrameworkAdmin fwAdmin = null; + + Manipulator manipulator = null; + + /** + * If the manifest of the target fw implementation has Constants.BUNDLE_SYMBOLICNAME header, + * this constructor should be used. + * + * @param context + * @param ManipulatorAdmin + * @param Manipulator + * @param systemBundleSymbolicName + */ + public SimpleBundlesState(BundleContext context, FrameworkAdmin ManipulatorAdmin, Manipulator Manipulator, String systemBundleSymbolicName) { + super(); + this.context = context; + this.fwAdmin = ManipulatorAdmin; + // copy Manipulator object for avoiding modifying the parameters of the Manipulator. + this.manipulator = ManipulatorAdmin.getManipulator(); + this.manipulator.setConfigData(Manipulator.getConfigData()); + this.manipulator.setLauncherData(Manipulator.getLauncherData()); + this.systemBundleSymbolicName = systemBundleSymbolicName; + this.systemBundleName = null; + this.systemBundleVendor = null; + initialize(); + } + + /** + * If the manifest of the target fw implementation has not Constants.BUNDLE_SYMBOLICNAME header + * but , Constants.BUNDLE_NAME and BUNDLE_VERSION, + * this constructor should be used. + * + * @param context + * @param ManipulatorAdmin + * @param Manipulator + * @param systemBundleName + * @param systemBundleVender + */ + public SimpleBundlesState(BundleContext context, FrameworkAdmin ManipulatorAdmin, Manipulator Manipulator, String systemBundleName, String systemBundleVender) { + super(); + this.context = context; + this.fwAdmin = ManipulatorAdmin; + // copy Manipulator object for avoiding modifying the parameters of the Manipulator. + this.manipulator = ManipulatorAdmin.getManipulator(); + this.manipulator.setConfigData(Manipulator.getConfigData()); + this.manipulator.setLauncherData(Manipulator.getLauncherData()); + this.systemBundleSymbolicName = null; + this.systemBundleName = systemBundleName; + this.systemBundleVendor = systemBundleVender; + initialize(); + } + + public BundleInfo[] getExpectedState() throws FrameworkAdminRuntimeException { + if (!fwAdmin.isActive()) + throw new FrameworkAdminRuntimeException("FrameworkAdmin creates this object is no more available.", FrameworkAdminRuntimeException.FRAMEWORKADMIN_UNAVAILABLE); + return Utils.getBundleInfosFromList(this.bundleInfosList); + } + + /* + * Just return required bundles. + * + * @see org.eclipse.equinox.frameworkadmin.BundlesState#getPrerequisteBundles(org.eclipse.equinox.frameworkadmin.BundleInfo) + */ + public BundleInfo[] getPrerequisteBundles(BundleInfo bInfo) { + String location = bInfo.getLocation(); + final String requiredBundles = Utils.getManifestMainAttributes(location, Constants.REQUIRE_BUNDLE); + if (requiredBundles == null) + return new BundleInfo[] {this.getSystemBundle()}; + + String[] clauses = Utils.getClauses(requiredBundles); + List list = new LinkedList(); + for (int i = 0; i < clauses.length; i++) + list.add(Utils.getPathFromClause(clauses[i])); + + List ret = new LinkedList(); + ret.add(this.getSystemBundle()); + for (Iterator ite = this.bundleInfosList.iterator(); ite.hasNext();) { + BundleInfo currentBInfo = (BundleInfo) ite.next(); + String currentLocation = currentBInfo.getLocation(); + String currentSymbolicName = Utils.getManifestMainAttributes(currentLocation, Constants.BUNDLE_SYMBOLICNAME); + if (currentSymbolicName == null) + continue; + currentSymbolicName = Utils.getPathFromClause(currentSymbolicName); + for (Iterator ite2 = list.iterator(); ite2.hasNext();) { + String symbolicName = (String) ite2.next(); + if (symbolicName.equals(currentSymbolicName)) { + ret.add(currentBInfo); + break; + } + } + } + return Utils.getBundleInfosFromList(ret); + } + + public BundleInfo getSystemBundle() { + if (this.systemBundleSymbolicName == null) { + for (Iterator ite = this.bundleInfosList.iterator(); ite.hasNext();) { + BundleInfo bInfo = (BundleInfo) ite.next(); + // if (bInfo.getStartLevel() != 1) + // return null;; + String location = bInfo.getLocation(); + String bundleName = Utils.getManifestMainAttributes(location, Constants.BUNDLE_NAME); + if (systemBundleName.equals(bundleName)) { + String bundleVendor = Utils.getManifestMainAttributes(location, Constants.BUNDLE_VENDOR); + if (systemBundleVendor.equals(bundleVendor)) + return bInfo; + } + } + return null; + } + for (Iterator ite = this.bundleInfosList.iterator(); ite.hasNext();) { + BundleInfo bInfo = (BundleInfo) ite.next(); + String location = bInfo.getLocation(); + String symbolicName = Utils.getManifestMainAttributes(location, Constants.BUNDLE_SYMBOLICNAME); + symbolicName = Utils.getPathFromClause(symbolicName); + if (this.systemBundleSymbolicName.equals(symbolicName)) + return bInfo; + } + return null; + } + + public BundleInfo[] getSystemFragmentedBundles() { + BundleInfo systemBInfo = this.getSystemBundle(); + if (systemBInfo == null) + return NULL_BUNDLEINFOS; + + List list = new LinkedList(); + for (Iterator ite = this.bundleInfosList.iterator(); ite.hasNext();) { + BundleInfo bInfo = (BundleInfo) ite.next(); + String location = bInfo.getLocation(); + String manifestVersion = Utils.getManifestMainAttributes(location, Constants.BUNDLE_MANIFESTVERSION); + if (manifestVersion == null) + continue; + if (manifestVersion.equals("1") || manifestVersion.equals("1.0")) + continue; + + String fragmentHost = Utils.getManifestMainAttributes(location, Constants.FRAGMENT_HOST); + if (fragmentHost == null) + continue; + int index = fragmentHost.indexOf(";"); + if (index == -1) + continue; + String symbolicName = fragmentHost.substring(0, index).trim(); + String parameter = fragmentHost.substring(index + 1).trim(); + // TODO What to do ,in case of alias name of system bundle is not used ? + if (symbolicName.equals(Constants.SYSTEM_BUNDLE_SYMBOLICNAME)) + if (parameter.equals(Constants.EXTENSION_DIRECTIVE + ":=" + Constants.EXTENSION_FRAMEWORK)) { + list.add(location); + break; + } + } + return Utils.getBundleInfosFromList(list); + } + + public String[] getUnsatisfiedConstraints(BundleInfo bInfo) throws FrameworkAdminRuntimeException { + throw new FrameworkAdminRuntimeException("getUnsatisfiedConstraints(BundleInfo bInfo) is not supported in this implementation", FrameworkAdminRuntimeException.UNSUPPORTED_OPERATION); + } + + private void initialize() { + this.bundleInfosList.clear(); + LauncherData launcherData = manipulator.getLauncherData(); + ConfigData configData = manipulator.getConfigData(); + File fwJar = getFwJar(launcherData);; + + if (fwJar == null) + throw new IllegalStateException("launcherData.getLauncherConfigFile() == null && fwJar is not set."); + // No fw persistent data location is taken into consideration. + + BundleInfo[] bInfos = configData.getBundles(); + for (int j = 0; j < bInfos.length; j++) + this.installBundle(bInfos[j]); + + if (getSystemBundle() == null) { + try { + BundleInfo sysBInfo = new BundleInfo(launcherData.getFwJar().toURL().toExternalForm(), 0, true); + this.installBundle(sysBInfo); + + } catch (MalformedURLException e) { + // Nothign to do because never happens. + e.printStackTrace(); + } + } + } + + public void installBundle(BundleInfo bInfo) throws FrameworkAdminRuntimeException { + + String newLocation = bInfo.getLocation(); + Dictionary newManifest = Utils.getOSGiManifest(newLocation); + String newSymbolicName = (String) newManifest.get(Constants.BUNDLE_SYMBOLICNAME); + String newVersion = (String) newManifest.get(Constants.BUNDLE_VERSION); + //System.out.println("> currentInstalledBundles.length=" + currentInstalledBundles.length); + boolean found = false; + for (Iterator ite = this.bundleInfosList.iterator(); ite.hasNext();) { + BundleInfo currentBInfo = (BundleInfo) ite.next(); + String location = currentBInfo.getLocation(); + if (newLocation.equals(location)) { + found = true; + break; + } + Dictionary manifest = Utils.getOSGiManifest(location); + String symbolicName = (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME); + String version = (String) manifest.get(Constants.BUNDLE_VERSION); + if (newSymbolicName != null && newVersion != null) + if (newSymbolicName.equals(symbolicName) && newVersion.equals(version)) { + found = true; + break; + } + } + if (!found) { + this.bundleInfosList.add(bInfo); + } + } + + // public String toString() { + // if (state == null) + // return null; + // StringBuffer sb = new StringBuffer(); + // BundleDescription[] bundleDescriptions = state.getBundles(); + // for (int i = 0; i < bundleDescriptions.length; i++) { + // sb.append(bundleDescriptions[i].getBundleId() + ":"); + // sb.append(bundleDescriptions[i].toString() + "("); + // sb.append(bundleDescriptions[i].isResolved() + ")"); + // String[] ees = bundleDescriptions[i].getExecutionEnvironments(); + // for (int j = 0; j < ees.length; j++) + // sb.append(ees[j] + " "); + // sb.append("\n"); + // } + // sb.append("PlatformProperties:\n"); + // Dictionary[] dics = state.getPlatformProperties(); + // for (int i = 0; i < dics.length; i++) { + // for (Enumeration enum = dics[i].keys(); enum.hasMoreElements();) { + // String key = (String) enum.nextElement(); + // String value = (String) dics[i].get(key); + // sb.append(" (" + key + "," + value + ")\n"); + // } + // } + // sb.append("\n"); + // return sb.toString(); + // } + + public boolean isFullySupported() { + return false; + } + + public boolean isResolved() throws FrameworkAdminRuntimeException { + throw new FrameworkAdminRuntimeException("isResolved() is not supported in this implementation", FrameworkAdminRuntimeException.UNSUPPORTED_OPERATION); + } + + public boolean isResolved(BundleInfo bInfo) throws FrameworkAdminRuntimeException { + throw new FrameworkAdminRuntimeException("isResolved(BundleInfo bInfo) is not supported in this implementation", FrameworkAdminRuntimeException.UNSUPPORTED_OPERATION); + } + + public void resolve(boolean increment) throws FrameworkAdminRuntimeException { + throw new FrameworkAdminRuntimeException("resolve(boolean increment) is not supported in this implementation", FrameworkAdminRuntimeException.UNSUPPORTED_OPERATION); + } + + public void uninstallBundle(BundleInfo bInfo) throws FrameworkAdminRuntimeException { + String targetLocation = bInfo.getLocation(); + int index = -1; + for (Iterator ite = this.bundleInfosList.iterator(); ite.hasNext();) { + index++; + BundleInfo currentBInfo = (BundleInfo) ite.next(); + String location = currentBInfo.getLocation(); + if (targetLocation.equals(location)) { + break; + } + } + if (index != -1) + this.bundleInfosList.remove(index); + } + +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/frameworkadmin/utils/Utils.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/frameworkadmin/utils/Utils.java new file mode 100644 index 000000000..aaa4efc97 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/frameworkadmin/utils/Utils.java @@ -0,0 +1,486 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.frameworkadmin.utils; + +import java.io.*; +import java.net.*; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import org.eclipse.equinox.frameworkadmin.BundleInfo; + +public class Utils { + private final static String PATH_SEP = "/"; + + /** + * Overwrite all properties of from to the properties of to. Return the result of to. + * + * @param to Properties whose keys and values of other Properties will be appended to. + * @param from Properties whose keys and values will be set to the other properties. + * @return Properties as a result of this method. + */ + public static Properties appendProperties(Properties to, Properties from) { + if (from != null) { + if (to == null) + to = new Properties(); + // printoutProperties(System.out, "to", to); + // printoutProperties(System.out, "from", from); + + for (Enumeration enumeration = from.keys(); enumeration.hasMoreElements();) { + String key = (String) enumeration.nextElement(); + to.setProperty(key, from.getProperty(key)); + } + } + // printoutProperties(System.out, "to", to); + return to; + } + + public static void checkAbsoluteDir(File file, String dirName) throws IllegalArgumentException { + if (file == null) + throw new IllegalArgumentException(dirName + " is null"); + if (!file.isAbsolute()) + throw new IllegalArgumentException(dirName + " is not absolute path. file=" + file.getAbsolutePath()); + if (!file.isDirectory()) + throw new IllegalArgumentException(dirName + " is not directory. file=" + file.getAbsolutePath()); + } + + public static void checkAbsoluteFile(File file, String dirName) {//throws ManipulatorException { + if (file == null) + throw new IllegalArgumentException(dirName + " is null"); + if (!file.isAbsolute()) + throw new IllegalArgumentException(dirName + " is not absolute path. file=" + file.getAbsolutePath()); + if (file.isDirectory()) + throw new IllegalArgumentException(dirName + " is not file but directory"); + } + + public static URL checkFullUrl(URL url, String urlName) throws IllegalArgumentException {//throws ManipulatorException { + if (url == null) + throw new IllegalArgumentException(urlName + " is null"); + if (!url.getProtocol().endsWith("file")) + return url; + File file = new File(url.getFile()); + if (!file.isAbsolute()) + throw new IllegalArgumentException(urlName + "(" + url + ") does not have absolute path"); + if (file.getAbsolutePath().startsWith(PATH_SEP)) + return url; + try { + return getUrl("file", null, PATH_SEP + file.getAbsolutePath()); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(urlName + "(" + "file:" + PATH_SEP + file.getAbsolutePath() + ") is not fully quallified", e); + } + } + + public static void createParentDir(File file) throws IOException { + // try { + createParentDir(file, new Stack()); + // } catch (IOException e) { + // throw new IOException("Fail to createParentDir(" + file.getAbsolutePath() + ")", e); + //Fs } + } + + private static void createParentDir(File file, Stack stack) throws IOException { + // file.getParent() + // + // URL url = getUrl("file",null,file.getAbsolutePath()); + // StringTokenizer tokenizer = new StringTokenizer(url.getFile(),"/"); + // + + File parent = file.getParentFile(); + if (parent.exists()) { + while (!stack.empty()) { + File child = (File) stack.pop(); + if (!child.mkdir()) + throw new IOException("Fail to mkdir of " + child.toString()); + } + return; + } + stack.push(parent); + createParentDir(parent, stack); + } + + public static void deleteDir(File file) throws IOException { + if (file.isFile()) { + if (!file.delete()) + throw new IOException("Fail to delete File(" + file.getAbsolutePath() + ")"); + return; + } + File[] children = file.listFiles(); + for (int i = 0; i < children.length; i++) { + deleteDir(children[i]); + } + if (!file.delete()) + throw new IOException("Fail to delete Dir(" + file.getAbsolutePath() + ")"); + return; + } + + /** + * First, it replaces File.seperator of relativePath to "/". + * If relativePath is in URL format, return its URL. + * Otherwise, create absolute URL based on the baseUrl. + * + * @param relativePath + * @param baseUrl + * @return URL + * @throws MalformedURLException + */ + public static URL formatUrl(String relativePath, URL baseUrl) throws MalformedURLException {//throws ManipulatorException { + relativePath = Utils.replaceAll(relativePath, File.separator, "/"); + URL url = null; + try { + url = new URL(relativePath); + if (url.getProtocol().equals("file")) + if (!(new File(url.getFile())).isAbsolute()) + url = getUrlInFull(relativePath, baseUrl); + return url; + } catch (MalformedURLException e) { + return getUrlInFull(relativePath, baseUrl); + } + } + + public static BundleInfo[] getBundleInfosFromList(List list) { + if (list == null) + return new BundleInfo[0]; + BundleInfo[] ret = new BundleInfo[list.size()]; + list.toArray(ret); + return ret; + } + + public static String getPathFromClause(String clause) { + if (clause == null) + return null; + if (clause.indexOf(";") != -1) + clause = clause.substring(0, clause.indexOf(";")); + return clause.trim(); + } + + public static String[] getClauses(String header) { + StringTokenizer token = new StringTokenizer(header, ","); + List list = new LinkedList(); + while (token.hasMoreTokens()) { + list.add(token.nextToken()); + } + String[] ret = new String[list.size()]; + list.toArray(ret); + return ret; + } + + public static String[] getClausesManifestMainAttributes(String location, String name) { + return getClauses(getManifestMainAttributes(location, name)); + } + + public static String getManifestMainAttributes(String location, String name) { + try { + URL url = new URL("jar:" + location + "!/"); + JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); + Manifest manifest = jarConnection.getManifest(); + Attributes attributes = manifest.getMainAttributes(); + String value = attributes.getValue(name); + return value == null ? null : value.trim(); + } catch (MalformedURLException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + public static Dictionary getOSGiManifest(String location) { + try { + URL url = new URL("jar:" + location + "!/"); + JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); + Manifest manifest = jarConnection.getManifest(); + Attributes attributes = manifest.getMainAttributes(); + // Set set = attributes.keySet(); + Hashtable table = new Hashtable(); + for (java.util.Iterator ite = attributes.keySet().iterator(); ite.hasNext();) { + // Object obj = ite.next(); + //System.out.println(obj.getClass().getName()); + + String key = (String) ite.next().toString(); + // While table contains non OSGiManifest, it doesn't matter. + table.put(key, attributes.getValue(key)); + // System.out.println("key=" + key + " value=" + value); + } + // System.out.println(""); + return table; + } catch (MalformedURLException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + public static String getRelativePath(File target, File from) { + + String targetPath = Utils.replaceAll(target.getAbsolutePath(), File.separator, PATH_SEP); + String fromPath = Utils.replaceAll(from.getAbsolutePath(), File.separator, PATH_SEP); + + String[] targetTokens = Utils.getTokens(targetPath, PATH_SEP); + String[] fromTokens = Utils.getTokens(fromPath, PATH_SEP); + int index = -1; + for (int i = 0; i < fromTokens.length; i++) + if (fromTokens[i].equals(targetTokens[i])) + index = i; + else + break; + + StringBuffer sb = new StringBuffer(); + for (int i = index + 1; i < fromTokens.length; i++) + sb.append(".." + PATH_SEP); + + for (int i = index + 1; i < targetTokens.length; i++) + if (i != targetTokens.length - 1) + sb.append(targetTokens[i] + PATH_SEP); + else + sb.append(targetTokens[i]); + return sb.toString(); + } + + public static String getRelativePath(URL target, URL from) throws IllegalArgumentException { + + if (!target.getProtocol().equals(from.getProtocol())) + throw new IllegalArgumentException("Protocols of target(=" + target + ") and from(=" + from + ") does NOT equal"); + + if (target.getHost() != null && target.getHost().length() != 0) { + //System.out.println("target.getHost()=" + target.getHost()); + if (from.getHost() != null && from.getHost().length() != 0) { + if (!target.getHost().equals(from.getHost())) + throw new IllegalArgumentException("Hosts of target(=" + target + ") and from(=" + from + ") does NOT equal"); + if (target.getPort() != (from.getPort())) + throw new IllegalArgumentException("Ports of target(=" + target + ") and from(=" + from + ") does NOT equal"); + } else + throw new IllegalArgumentException("While Host of target(=" + target + ") is set, Host of from is null.target.getHost()=" + target.getHost()); + } else if (from.getHost() != null && from.getHost().length() != 0) + throw new IllegalArgumentException("While Host of from(=" + from + ") is set, Host of target is null"); + + String targetPath = target.getFile(); + String fromPath = from.getFile(); + + String[] targetTokens = Utils.getTokens(targetPath, PATH_SEP); + String[] fromTokens = Utils.getTokens(fromPath, PATH_SEP); + int index = -1; + for (int i = 0; i < fromTokens.length; i++) + if (fromTokens[i].equals(targetTokens[i])) + index = i; + else + break; + + StringBuffer sb = new StringBuffer(); + for (int i = index + 1; i < fromTokens.length; i++) + sb.append(".." + PATH_SEP); + + for (int i = index + 1; i < targetTokens.length; i++) + if (i != targetTokens.length - 1) + sb.append(targetTokens[i] + PATH_SEP); + else + sb.append(targetTokens[i]); + return sb.toString(); + } + + /** + * This method will be called for create a backup file. + * + * @param file target file + * @return File backup file whose filename consists of "hogehoge.yyyyMMddHHmmss.ext" or + * "hogehoge.yyyyMMddHHmmss". + */ + public static File getSimpleDataFormattedFile(File file) { + SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); + String date = df.format(new Date()); + String filename = file.getName(); + int index = filename.lastIndexOf("."); + if (index != -1) + filename = filename.substring(0, index) + "." + date + "." + filename.substring(index + 1); + else + filename = filename + "." + date; + File dest = new File(file.getParentFile(), filename); + return dest; + } + + // public static URL getAbsoluteUrl(String relativePath, URL baseUrl) throws FwLauncherException { + // relativePath = Utils.replaceAll(relativePath, File.separator, "/"); + // try { + // return new URL(baseUrl, relativePath); + // } catch (MalformedURLException e) { + // throw new FwLauncherException("Absolute URL cannot be created. \nrelativePath=" + relativePath + ",baseUrl=" + baseUrl, e, FwLauncherException.URL_FORMAT_ERROR); + // } + // } + + // public static void setProperties(Properties to, Properties from, String key) { + // if (from != null) { + // String value = from.getProperty(key); + // if (value != null) { + // if (to != null) + // to = new Properties(); + // to.setProperty(key, value); + // } + // } + // } + + // public static int getIntProperties(Properties props, String key) {//throws ManipulatorException { + // if (props == null) + // throw new IllegalArgumentException("props == null"); + // String value = null; + // try { + // value = props.getProperty(key); + // return Integer.parseInt(value); + // } catch (NumberFormatException nfe) { + // throw new ManipulatorException("key=" + key + ",value=" + value, nfe, ManipulatorException.OTHERS); + // } + // } + + public static String[] getTokens(String msg, String delim) { + return getTokens(msg, delim, false); + } + + public static String[] getTokens(String msg, String delim, boolean returnDelims) { + StringTokenizer targetST = new StringTokenizer(msg, delim, returnDelims); + String[] tokens = new String[targetST.countTokens()]; + ArrayList list = new ArrayList(targetST.countTokens()); + while (targetST.hasMoreTokens()) { + list.add(targetST.nextToken()); + } + list.toArray(tokens); + return tokens; + } + + public static URL getUrl(String protocol, String host, String file) throws MalformedURLException {// throws ManipulatorException { + file = Utils.replaceAll(file, File.separator, "/"); + return new URL(protocol, host, file); + } + + public static URL getUrlInFull(String path, URL from) throws MalformedURLException {//throws ManipulatorException { + Utils.checkFullUrl(from, "from"); + path = Utils.replaceAll(path, File.separator, "/"); + //System.out.println("from.toExternalForm()=" + from.toExternalForm()); + String fromSt = Utils.removeLastCh(from.toExternalForm(), '/'); + //System.out.println("fromSt=" + fromSt); + if (path.startsWith("/")) { + String fileSt = from.getFile(); + return new URL(fromSt.substring(0, fromSt.lastIndexOf(fileSt) - 1) + path); + } + return new URL(fromSt + "/" + path); + } + + /** + * Just used for debug. + * + * @param ps printstream + * @param name name of properties + * @param props properties whose keys and values will be printed out. + */ + public static void printoutProperties(PrintStream ps, String name, Properties props) { + if (props == null || props.size() == 0) { + ps.println("Props(" + name + ") is empty"); + return; + } + ps.println("Props(" + name + ")="); + for (Enumeration enumeration = props.keys(); enumeration.hasMoreElements();) { + String key = (String) enumeration.nextElement(); + ps.print("\tkey=" + key); + ps.println("\tvalue=" + props.getProperty(key)); + } + } + + public static String removeLastCh(String target, char ch) { + while (target.charAt(target.length() - 1) == ch) { + target = target.substring(0, target.length() - 1); + } + return target; + } + + public static String replaceAll(String st, String oldSt, String newSt) { + int index = -1; + while ((index = st.indexOf(oldSt)) != -1) { + st = st.substring(0, index) + newSt + st.substring(index + oldSt.length()); + } + return st; + } + + public static String shrinkPath(String target) { + String targetPath = Utils.replaceAll(target, File.separator, PATH_SEP); + String[] targetTokens = Utils.getTokens(targetPath, PATH_SEP); + //String[] fromTokens = Utils.getTokens(fromPath, PATH_SEP); + for (int i = 0; i < targetTokens.length; i++) + if (targetTokens[i].equals("")) { + targetTokens[i] = null; + } else if (targetTokens[i].equals(".")) { + targetTokens[i] = null; + } else if (targetTokens[i].equals("..")) { + int id = i - 1; + while (targetTokens[id] == null) { + id--; + } + targetTokens[id] = null; + } + + StringBuffer sb = new StringBuffer(); + if (targetPath.startsWith(PATH_SEP)) + sb.append(PATH_SEP); + for (int i = 0; i < targetTokens.length; i++) + if (targetTokens[i] != null) + sb.append(targetTokens[i] + PATH_SEP); + String ret = sb.toString(); + if (!targetPath.endsWith(PATH_SEP)) + ret = ret.substring(0, ret.lastIndexOf(PATH_SEP)); + return ret; + } + + /** + * Sort by increasing order of startlevels. + * + * @param bInfos array of BundleInfos to be sorted. + * @param initialBSL initial bundle start level to be used. + * @return sorted array of BundleInfos + */ + public static BundleInfo[] sortBundleInfos(BundleInfo[] bInfos, int initialBSL) { + SortedMap bslToList = new TreeMap(); + for (int i = 0; i < bInfos.length; i++) { + Integer sL = Integer.valueOf(bInfos[i].getStartLevel()); + if (sL.intValue() == BundleInfo.NO_LEVEL) + sL = new Integer(initialBSL); + List list = (List) bslToList.get(sL); + if (list == null) { + list = new LinkedList(); + bslToList.put(sL, list); + } + list.add(bInfos[i]); + } + + // bslToList is sorted by the key (StartLevel). + List bundleInfoList = new LinkedList(); + for (Iterator ite = bslToList.keySet().iterator(); ite.hasNext();) { + Integer sL = (Integer) ite.next(); + List list = (List) bslToList.get(sL); + for (Iterator ite2 = list.iterator(); ite2.hasNext();) { + BundleInfo bInfo = (BundleInfo) ite2.next(); + bundleInfoList.add(bInfo); + } + } + return getBundleInfosFromList(bundleInfoList); + } + + public static void validateUrl(URL url) {//throws ManipulatorException { + try {//test + URLConnection connection = url.openConnection(); + connection.connect(); + } catch (IOException e) { + throw new IllegalArgumentException("URL(" + url + ") cannot be connected.", e); + } + } +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorConstants.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorConstants.java new file mode 100644 index 000000000..a67ec9f96 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorConstants.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.simpleconfigurator.utils; + +public class SimpleConfiguratorConstants { + public static final String PARAMETER_BASEURL = "eclipse.simpleConfigurator.baseUrl"; + public static final String PROP_KEY_EXCLUSIVE_INSTALLATION = "org.eclipse.equinox.simpleconfigurator.exclusiveInstallation"; + + public static final String LAST_CONFIG_STAMP = "last.config.stamps"; //$NON-NLS-1$ + public static final String CONFIG_LIST = "bundles.txt"; //$NON-NLS-1$ + public static final String CONFIGURATOR_FOLDER = "simpleConfiguration"; //$NON-NLS-1$ + public static final String CONFIG_INI = "config.ini"; //$NON-NLS-1$ + public static final String PROP_KEY_CONFIGURL = "org.eclipse.equinox.simpleconfigurator.configUrl"; + +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorUtils.java b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorUtils.java new file mode 100644 index 000000000..5bfddb1ee --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorUtils.java @@ -0,0 +1,251 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.simpleconfigurator.utils; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; + +import org.eclipse.equinox.frameworkadmin.BundleInfo; +import org.eclipse.equinox.internal.frameworkadmin.utils.Utils; +import org.osgi.framework.*; +import org.osgi.service.startlevel.StartLevel; + +public class SimpleConfiguratorUtils { + + final static boolean DEBUG = false; + + public static final String SERVICE_PROP_VALUE_CONFIGURATOR_SYMBOLICNAME = "org.eclipse.equinox.simpleconfigurator"; + + public static boolean checkMatchEclipseJarNaming(String location, final String jarName) { + String filename = null; + if (location.indexOf(":") == -1) + filename = location; + else + filename = location.substring(location.lastIndexOf(":") + 1); + + if (location.indexOf("/") == -1) + filename = location; + else + filename = location.substring(location.lastIndexOf("/") + 1); + // filename must be "jarName"_"version".jar + //System.out.println("filename=" + filename); + if (!filename.endsWith(".jar")) + return false; + filename = filename.substring(0, filename.lastIndexOf(".jar")); + //System.out.println("filename=" + filename); + if (filename.lastIndexOf("_") == -1) + return false; + filename = filename.substring(0, filename.lastIndexOf("_")); + //System.out.println("filename=" + filename); + if (filename.indexOf("_") != -1) + return false; + if (filename.equals(jarName)) + return true; + return false; + } + + public static BundleInfo getBundleInfoFromBundle(BundleContext context, StartLevel startLevelService, Bundle bundle) { + String symbolicName = bundle.getSymbolicName(); + Dictionary manifest = context.getBundle().getHeaders(); + String versionSt = (String) manifest.get(Constants.BUNDLE_VERSION); + + BundleInfo bInfo = new BundleInfo(symbolicName, versionSt, bundle.getLocation(), startLevelService.getBundleStartLevel(bundle), startLevelService.isBundlePersistentlyStarted(bundle)); + return bInfo; + } + + public static String getBundleStateString(Bundle bundle) { + StringBuffer sb = new StringBuffer(); + sb.append(bundle.getLocation()); + sb.append(" : "); + switch (bundle.getState()) { + case Bundle.INSTALLED : + sb.append("INSTALLED"); + break; + case Bundle.ACTIVE : + sb.append("ACTIVE"); + break; + case Bundle.RESOLVED : + sb.append("RESOLVED"); + break; + case Bundle.STARTING : + sb.append("STARTING"); + break; + case Bundle.STOPPING : + sb.append("STOPPING"); + break; + case Bundle.UNINSTALLED : + sb.append("UNINSTALLED"); + break; + } + return sb.toString(); + } + + // public static BundleInfo[] mergeCurrentState(BundleContext context, StartLevel startLevelService, List bundleInfoList) throws FwLauncherException { + // // if (this.configApplier == null) + // // configApplier = new ConfigApplier(context, this); + // + // List currentList = getInstalledBundleInfosList(context,startLevelService); + // + // return mergeCurrentState(bundleInfoList, currentList); + // } + + public static List getInstalledBundleInfosList(BundleContext context, StartLevel startLevelService) { + Bundle[] bundles = context.getBundles(); + List currentList = new LinkedList(); + + for (int i = 0; i < bundles.length; i++) { + BundleInfo bInfo = getBundleInfoFromBundle(context, startLevelService, bundles[i]); + currentList.add(bInfo); + } + return currentList; + } + + public static String getListSt(List list) { + StringBuffer sb = new StringBuffer(); + for (Iterator ite2 = list.iterator(); ite2.hasNext();) { + BundleInfo bInfo = (BundleInfo) ite2.next(); + sb.append(bInfo.toString() + "\n"); + } + return sb.toString(); + } + + public static boolean isSystemBundleFragment(BundleContext context, Bundle bundle) { + //Bundle[] bundles = context.getBundles(); + String symbolicNameSystem = context.getBundle(0).getSymbolicName(); + String fragmentHost = (String) bundle.getHeaders().get(Constants.FRAGMENT_HOST); + if (fragmentHost != null) { + String symbolic = fragmentHost.substring(0, fragmentHost.indexOf(";")).trim(); + if (symbolic.equals(symbolicNameSystem)) + return true; + if (symbolic.equals(Constants.SYSTEM_BUNDLE_SYMBOLICNAME)) + return true; + } + return false; + } + + public static BundleInfo[] mergeState(List addedBundleInfoList, List currentBundleInfoList) { + for (Iterator ite = addedBundleInfoList.iterator(); ite.hasNext();) { + boolean duplicated = false; + BundleInfo bInfo = (BundleInfo) ite.next(); + for (Iterator currentIte = currentBundleInfoList.iterator(); currentIte.hasNext();) { + BundleInfo bInfoCurrent = (BundleInfo) currentIte.next(); + // int sl = startLevelService.getInitialBundleStartLevel(); + // if (bInfo.getStartLevel() != BundleInfo.NO_LEVEL) + // sl = bInfo.getStartLevel(); + if (bInfoCurrent.getLocation().equals(bInfo.getLocation())) { + bInfoCurrent.setStartLevel(bInfo.getStartLevel()); + bInfoCurrent.setMarkedAsStarted(bInfo.isMarkedAsStarted()); + duplicated = true; + break; + } + } + if (!duplicated) + currentBundleInfoList.add(bInfo); + } + return Utils.getBundleInfosFromList(currentBundleInfoList); + } + + public static List readConfiguration(URL url) throws IOException { + List bundles = new ArrayList(); + try { + // System.out.println("readConfiguration(URL url):url()=" + url); + // URL configFileUrl = getConfigFileUrl(); + // URL configFileUrl = Utils.getUrl("file",null, + // inputFile.getAbsolutePath()); + BufferedReader r = new BufferedReader(new InputStreamReader(url.openStream())); + // BufferedReader r = new BufferedReader(new FileReader(inputFile)); + + String line; + try { + URL baseUrl = new URL(url, "./"); + while ((line = r.readLine()) != null) { + if (line.startsWith("#")) + continue; + line = line.trim();// symbolicName,version,location,startlevel,expectedState + if (line.length() == 0) + continue; + + // (expectedState is an integer). + //System.out.println("line=" + line); + if (line.startsWith(SimpleConfiguratorConstants.PARAMETER_BASEURL + "=")) { + String baseUrlSt = line.substring((SimpleConfiguratorConstants.PARAMETER_BASEURL + "=").length()); + if (!baseUrlSt.endsWith("/")) + baseUrlSt += "/"; + baseUrl = new URL(url, baseUrlSt); +// if (DEBUG) +// System.out.println("baseUrl=" + baseUrl); + continue; + } + StringTokenizer tok = new StringTokenizer(line, ",", true); + String symbolicName = tok.nextToken(); + if (symbolicName.equals(",")) + symbolicName = null; + else + tok.nextToken(); // , + + String version = tok.nextToken(); + if (version.equals(",")) + version = null; + else + tok.nextToken(); // , + + String urlSt = tok.nextToken(); + if (urlSt.equals(",")) { + if (symbolicName != null && version != null) + urlSt = symbolicName + "_" + version + ".jar"; + else + urlSt = null; + } else + tok.nextToken(); // , + try { + new URL(urlSt); +// if (DEBUG) +// System.out.println("1 urlSt=" + urlSt); + } catch (MalformedURLException e) { + urlSt = Utils.getUrlInFull(urlSt, baseUrl).toExternalForm(); +// if (DEBUG) +// System.out.println("2 urlSt=" + urlSt); + } + + int sl = Integer.parseInt(tok.nextToken().trim()); + tok.nextToken(); // , + boolean markedAsStarted = Boolean.parseBoolean(tok.nextToken()); + // URL urlBundle = null; + // try { + // urlBundle = new URL(urlSt); + // } catch (MalformedURLException e) { + // urlBundle = Utils.getFullUrl(urlSt, baseUrl); + // } + + BundleInfo bInfo = new BundleInfo(symbolicName, version, urlSt, sl, markedAsStarted); + bundles.add(bInfo); + // System.out.println("tail line=" + line); + } + } finally { + try { + r.close(); + } catch (IOException ex) { + // ignore + } + } + } catch (MalformedURLException e) { + e.printStackTrace(); + // TODO log something + // bundleInfos = NULL_BUNDLEINFOS; + } + return bundles; + // bundleInfos = (BundleInfo[]) bundles.toArray(new + // BundleInfo[bundles.size()]); + } + +} diff --git a/bundles/org.eclipse.equinox.frameworkadmin/test/org/eclipse/incubator/configurator/util/UtilsTest.java b/bundles/org.eclipse.equinox.frameworkadmin/test/org/eclipse/incubator/configurator/util/UtilsTest.java new file mode 100644 index 000000000..73c542483 --- /dev/null +++ b/bundles/org.eclipse.equinox.frameworkadmin/test/org/eclipse/incubator/configurator/util/UtilsTest.java @@ -0,0 +1,122 @@ +///** +// * +// */ +//package org.eclipse.incubator.configurator.util; +// +//import java.net.MalformedURLException; +//import java.net.URL; +// +//import junit.framework.*; +// +//import org.eclipse.equinox.internal.frameworkadmin.utils.*; +// +///** +// * @author iyamasak +// * +// */ +//public class UtilsTest extends TestCase { +// +// /** +// * @param name +// */ +// public UtilsTest(String name) { +// super(name); +// } +// +// /* (non-Javadoc) +// * @see junit.framework.TestCase#setUp() +// */ +// protected void setUp() throws Exception { +// super.setUp(); +// } +// +// /* (non-Javadoc) +// * @see junit.framework.TestCase#tearDown() +// */ +// protected void tearDown() throws Exception { +// super.tearDown(); +// } +// +// // /** +// // * Test method for {@link org.eclipse.configMan.internal.util.Utils#getUrl(java.lang.String, java.lang.String, java.lang.String)}. +// // */ +// // public void testGetUrl() { +// // fail("Not yet implemented"); +// // } +// +// /** +// * Test method for {@link Utils#getRelativePath(java.net.URL, java.net.URL)}. +// */ +// public void testGetRelativePath() { +// //URL target; +// //URL from; +// try { +// URL target = new URL("http", "www.ntt.co.jp", "dir1/dir2/target.html"); +// URL from = new URL("http", "www.ntt.co.jp", "dir1/dir3/dir4/from.html"); +// String expected = "../../../dir2/target.html"; +// String ret = Utils.getRelativePath(target, from); +// assertEquals(expected, ret); +// +// expected = "../../dir3/dir4/from.html"; +// ret = Utils.getRelativePath(from, target); +// assertEquals(expected, ret); +// +// try { +// target = new URL("http", "www.ntt.co.jp", "dir1/dir2/target.html"); +// from = new URL("http", "www.ibm.com", "dir1/dir3/dir4/from.html"); +// ret = Utils.getRelativePath(target, from); +// fail("IllegalArgumentException must be thrown"); +// } catch (IllegalArgumentException e) { +// +// } +// try { +// target = new URL("file", null, "dir2/target.html"); +// from = new URL("http", "www.ntt.co.jp", "dir1/dir3/dir4/from.html"); +// ret = Utils.getRelativePath(target, from); +// fail("IllegalArgumentException must be thrown"); +// } catch (IllegalArgumentException e) { +// +// } +// } catch (MalformedURLException e) { +// e.printStackTrace(); +// +// } +// +// } +// +// /** +// * Test method for {@link Utils#replaceAll(java.lang.String, java.lang.String, java.lang.String)}. +// */ +// public void testReplaceAll() { +// String st = "tere/eerere//ty/d"; +// String expected = "tere\\eerere\\\\ty\\d"; +// String oldSt = "/"; +// String newSt = "\\"; +// String ret = Utils.replaceAll(st, oldSt, newSt); +// assertEquals(expected, ret); +// } +// +// /** +// * Test method for {@link Utils#getTokens(java.lang.String, java.lang.String)}. +// */ +// public void testGetTokens() { +// String st = "/AAAA/BB//CC/D/"; +// String[] expected = {"AAAA", "BB", "CC", "D"}; +// String delim = "/"; +// String[] ret = Utils.getTokens(st, delim); +// assertEquals("lengths must equal.", ret.length, expected.length); +// for (int i = 0; i < ret.length; i++) +// assertEquals("each elements must equal.", expected[i], ret[i]); +// } +// +// /** +// * Test method for {@link Utils#removeLastCh(String target, char ch)}. +// */ +// public void testRemoveLastCh() { +// String target = "ddddaaaaaaaa"; +// String expected = "dddd"; +// char ch = 'a'; +// String ret = Utils.removeLastCh(target, ch); +// assertEquals(expected, ret); +// } +//} |