Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: eaf97101e7986753fa01c5f6e53977965479edde (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*******************************************************************************
 * 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;
		}
	}
}

Back to the top