| /******************************************************************************* |
| * Copyright (c) 2005, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.osgi.internal.hookregistry; |
| |
| import java.io.DataInputStream; |
| import java.io.DataOutputStream; |
| import java.io.IOException; |
| import java.util.Dictionary; |
| import org.eclipse.osgi.container.Module; |
| import org.eclipse.osgi.container.ModuleContainer; |
| import org.eclipse.osgi.container.ModuleContainerAdaptor; |
| import org.eclipse.osgi.container.ModuleContainerAdaptor.ModuleEvent; |
| import org.eclipse.osgi.container.ModuleRevision; |
| import org.eclipse.osgi.container.ModuleRevisionBuilder; |
| import org.eclipse.osgi.storage.BundleInfo.Generation; |
| import org.osgi.framework.BundleException; |
| |
| /** |
| * A StorageHookFactory hooks into the persistent storage loading and saving of bundle {@link Generation generations}. |
| * A factory creates StorageHook instances that get associated with each Generation object installed.<p> |
| * @see Generation#getStorageHook(Class) |
| * @param <S> the StorageHook type |
| * @param <L> the load context type |
| * @param <H> the save context type |
| */ |
| public abstract class StorageHookFactory<S, L, H extends StorageHookFactory.StorageHook<S, L>> { |
| protected final String KEY = this.getClass().getName().intern(); |
| |
| /** |
| * Returns the storage version of this storage hook. This version |
| * is used by the storage to check the consistency of cached persistent |
| * data. Any time a storage hook changes the format of its persistent |
| * data the storage version should be incremented. |
| * @return the storage version of this storage hook |
| */ |
| public abstract int getStorageVersion(); |
| |
| /** |
| * Returns the implementation class name for the hook implementation |
| * @return the implementation class name for the hook implementation |
| */ |
| public final String getKey() { |
| return KEY; |
| } |
| |
| /** |
| * Returns true if the persisted version is compatible with the |
| * current version of this storage hook. The default implementation |
| * returns true if the specified version is identical to the current |
| * version. Implementations must override this method if they |
| * want to support other (older) versions for migration purposes. |
| * @param version the persisted version |
| * @return true if the persisted version is compatible with |
| * the current version. |
| */ |
| public boolean isCompatibleWith(int version) { |
| return getStorageVersion() == version; |
| } |
| |
| /** |
| * Creates a save context object for a storage hook. The |
| * save context is passed to the {@link StorageHook#save(Object, DataOutputStream)} |
| * for each generation being persisted by the framework. |
| * @return a save context object |
| */ |
| public S createSaveContext() { |
| return null; |
| } |
| |
| /** |
| * Creates a load context object for a storage hook. The |
| * load context is passed to the {@link StorageHook#load(Object, DataInputStream)} |
| * for each generation being loaded from persistent storage |
| * by the framework. |
| * @param version the persistent version |
| * @return the load context object |
| */ |
| public L createLoadContext(int version) { |
| return null; |
| } |
| |
| /** |
| * Creates a storage hook for the specified generation. |
| * @param generation the generation for the storage hook |
| * @return a storage hook |
| */ |
| protected abstract H createStorageHook(Generation generation); |
| |
| /** |
| * Creates a storage hook for the specified generation and checks that the |
| * factory class of the storage hook equals the class of this storage hook |
| * factory. |
| * |
| * @param generation - The generation for which a storage hook should be |
| * created. |
| * @return A newly created storage hook. |
| * @throws IllegalStateException - If the factory class of the storage hook |
| * is not equal to the class of this storage hook factory. |
| */ |
| public final H createStorageHookAndValidateFactoryClass(Generation generation) { |
| H result = createStorageHook(generation); |
| Class<?> factoryClass = getClass(); |
| Class<?> factoryClassOfStorageHook = result.getFactoryClass(); |
| if (!factoryClass.equals(factoryClassOfStorageHook)) |
| throw new IllegalStateException(String.format("The factory class '%s' of storage hook '%s' does not match the creating factory class of '%s'", factoryClassOfStorageHook.getName(), result, factoryClass.getName())); //$NON-NLS-1$ |
| return result; |
| } |
| |
| /** |
| * A storage hook for a specific generation object. This hook |
| * is responsible for persisting and loading data associated |
| * with a specific generation. |
| * |
| * @param <S> the save context type |
| * @param <L> the load context type |
| */ |
| public static abstract class StorageHook<S, L> { |
| private final Class<? extends StorageHookFactory<S, L, ? extends StorageHook<S, L>>> factoryClass; |
| private final Generation generation; |
| |
| public StorageHook(Generation generation, Class<? extends StorageHookFactory<S, L, ? extends StorageHook<S, L>>> factoryClass) { |
| this.generation = generation; |
| this.factoryClass = factoryClass; |
| } |
| |
| /** |
| * The generation associated with this hook. |
| * @return the generation associated with this hook. |
| */ |
| public Generation getGeneration() { |
| return generation; |
| } |
| |
| /** |
| * Initializes this storage hook with the content of the specified bundle manifest. |
| * This method is called when a bundle is installed or updated. |
| * @param manifest the bundle manifest to load into this storage hook |
| * @throws BundleException if any error occurs |
| */ |
| public abstract void initialize(Dictionary<String, String> manifest) throws BundleException; |
| |
| /** |
| * Allows a builder to be modified before it is used by the framework to create a {@link ModuleRevision revision} |
| * associated with the bundle {@link #getGeneration() generation} being installed or updated. |
| * @param operation The lifecycle operation event that is in progress using the supplied builder. |
| * This will be either {@link ModuleEvent#INSTALLED installed} or {@link ModuleEvent#UPDATED updated}. |
| * @param origin The module which originated the lifecycle operation. The origin may be {@code null} for |
| * {@link ModuleEvent#INSTALLED installed} operations. This is the module |
| * passed to the {@link ModuleContainer#install(Module, String, ModuleRevisionBuilder, Object) install} or |
| * {@link ModuleContainer#update(Module, ModuleRevisionBuilder, Object) update} method. |
| * @param builder the builder that will be used to create a new {@link ModuleRevision}. |
| * @return The modified builder or a completely new builder to be used by the bundle. A {@code null} value |
| * indicates the original builder should be used, which may have been modified by adding requirements or |
| * capabilities. |
| * @see ModuleContainerAdaptor#adaptModuleRevisionBuilder(ModuleEvent, Module, ModuleRevisionBuilder, Object) |
| */ |
| public ModuleRevisionBuilder adaptModuleRevisionBuilder(ModuleEvent operation, Module origin, ModuleRevisionBuilder builder) { |
| // do nothing |
| return null; |
| } |
| |
| /** |
| * Loads the data from the specified |
| * input stream into the storage hook. This method is called during startup to |
| * load all the persistently installed bundles. <p> |
| * It is important that this method and the {@link #save(Object, DataOutputStream)} method |
| * stay in sync. This method must be able to successfully read the data saved by the |
| * {@link #save(Object, DataOutputStream)} method. |
| * @param is an input stream used to load the storage hook's data from. |
| * @see #save(Object, DataOutputStream) |
| * @throws IOException if any error occurs |
| */ |
| public abstract void load(L loadContext, DataInputStream is) throws IOException; |
| |
| /** |
| * Saves the data from this storage hook into the specified output stream. This method |
| * is called if some persistent data has changed for the bundle. <p> |
| * It is important that this method and the {@link #load(Object, DataInputStream)} |
| * method stay in sync. This method must be able to save data which the |
| * {@link #load(Object, DataInputStream)} method can ready successfully. |
| * @see #load(Object, DataInputStream) |
| * @param os an output stream used to save the storage hook's data from. |
| * @throws IOException if any error occurs |
| */ |
| public abstract void save(S saveContext, DataOutputStream os) throws IOException; |
| |
| /** |
| * Gets called during {@link Generation#delete()} to inform the hook that the generation |
| * associated with the hook is being deleted. |
| */ |
| public void deletingGeneration() { |
| // do nothing by default |
| } |
| |
| /** |
| * Validates the data in this storage hook, if the data is invalid then an illegal state |
| * exception is thrown |
| * @throws IllegalStateException if the data is invalid |
| */ |
| public void validate() throws IllegalStateException { |
| // do nothing by default |
| } |
| |
| /** |
| * The storage hook factory class of this storage hook |
| * @return the storage hook factory class |
| */ |
| public Class<? extends StorageHookFactory<S, L, ? extends StorageHook<S, L>>> getFactoryClass() { |
| return factoryClass; |
| } |
| } |
| } |