1 /*******************************************************************************
2  * Copyright (c) 2013, 2017 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.osgi.tests.hooks.framework.storage.a;
15 
16 import java.io.ByteArrayInputStream;
17 import java.io.ByteArrayOutputStream;
18 import java.io.DataInputStream;
19 import java.io.DataOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.net.URLConnection;
23 import java.util.Collections;
24 import java.util.Dictionary;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.concurrent.atomic.AtomicInteger;
28 import java.util.jar.Attributes;
29 import java.util.jar.JarOutputStream;
30 import java.util.jar.Manifest;
31 import org.eclipse.osgi.container.Module;
32 import org.eclipse.osgi.container.ModuleContainerAdaptor.ModuleEvent;
33 import org.eclipse.osgi.container.ModuleRevisionBuilder;
34 import org.eclipse.osgi.container.ModuleRevisionBuilder.GenericInfo;
35 import org.eclipse.osgi.internal.hookregistry.ActivatorHookFactory;
36 import org.eclipse.osgi.internal.hookregistry.HookConfigurator;
37 import org.eclipse.osgi.internal.hookregistry.HookRegistry;
38 import org.eclipse.osgi.internal.hookregistry.StorageHookFactory;
39 import org.eclipse.osgi.storage.BundleInfo.Generation;
40 import org.osgi.framework.BundleActivator;
41 import org.osgi.framework.BundleContext;
42 import org.osgi.framework.Constants;
43 import org.osgi.framework.Version;
44 import org.osgi.framework.namespace.BundleNamespace;
45 import org.osgi.framework.namespace.IdentityNamespace;
46 
47 public class TestHookConfigurator implements HookConfigurator {
48 	private static class TestStorageHookFactory extends StorageHookFactory<Object, Object, TestStorageHookFactory.TestStorageHook> {
49 		private static class TestStorageHook extends StorageHookFactory.StorageHook<Object, Object> {
50 			private static AtomicInteger adaptCount = new AtomicInteger(1);
51 
TestStorageHook(Generation generation, Class clazz)52 			public TestStorageHook(Generation generation, Class clazz) {
53 				super(generation, clazz);
54 			}
55 
56 			@Override
initialize(Dictionary manifest)57 			public void initialize(Dictionary manifest) {
58 				// Nothing
59 			}
60 
61 			@Override
load(Object loadContext, DataInputStream is)62 			public void load(Object loadContext, DataInputStream is) {
63 				if (TestHookConfigurator.failLoad) {
64 					// will force a clean
65 					throw new IllegalArgumentException();
66 				}
67 			}
68 
69 			@Override
save(Object saveContext, DataOutputStream os)70 			public void save(Object saveContext, DataOutputStream os) {
71 				// Nothing.
72 			}
73 
74 			@Override
validate()75 			public void validate() throws IllegalStateException {
76 				TestHookConfigurator.validateCalled = true;
77 				if (TestHookConfigurator.invalid)
78 					throw new IllegalStateException();
79 			}
80 
81 			@Override
deletingGeneration()82 			public void deletingGeneration() {
83 				TestHookConfigurator.deletingGenerationCalled = true;
84 			}
85 
86 			@Override
adaptModuleRevisionBuilder(ModuleEvent operation, Module origin, ModuleRevisionBuilder builder)87 			public ModuleRevisionBuilder adaptModuleRevisionBuilder(ModuleEvent operation, Module origin, ModuleRevisionBuilder builder) {
88 				if (TestHookConfigurator.replaceModuleBuilder) {
89 					ModuleRevisionBuilder replace = new ModuleRevisionBuilder();
90 					// try setting the ID to something which is checked during the test
91 					replace.setId(5678);
92 					replace.setSymbolicName("replace");
93 					replace.setVersion(Version.parseVersion("1.1.1"));
94 					replace.addCapability("replace", Collections.<String, String> emptyMap(), Collections.<String, Object> emptyMap());
95 					replace.addCapability(IdentityNamespace.IDENTITY_NAMESPACE, Collections.<String, String> emptyMap(), Collections.<String, Object> singletonMap(IdentityNamespace.IDENTITY_NAMESPACE, "replace"));
96 					replace.addCapability(BundleNamespace.BUNDLE_NAMESPACE, Collections.<String, String> emptyMap(), Collections.<String, Object> singletonMap(BundleNamespace.BUNDLE_NAMESPACE, "replace"));
97 					return replace;
98 				}
99 				if (TestHookConfigurator.adaptManifest) {
100 					// try setting the ID to something which is checked during the test
101 					builder.setId(5678);
102 					Map<String, String> dirs = Collections.emptyMap();
103 					Map<String, Object> attrs = new HashMap<>();
104 					attrs.put("test.file.path", getGeneration().getContent().getPath() + " - " + adaptCount.getAndIncrement());
105 					attrs.put("test.operation", operation.toString());
106 					attrs.put("test.origin", origin.getLocation());
107 					builder.addCapability("test.file.path", dirs, attrs);
108 				}
109 				if (TestHookConfigurator.adaptCapabilityAttribute) {
110 					for (GenericInfo c : builder.getCapabilities()) {
111 						if (BundleNamespace.BUNDLE_NAMESPACE.equals(c.getNamespace())) {
112 							c.getAttributes().put("matching.attribute", "testAttribute");
113 							c.getDirectives().put("matching.directive", "testDirective");
114 						}
115 					}
116 				}
117 				return builder;
118 			}
119 		}
120 
TestStorageHookFactory()121 		public TestStorageHookFactory() {
122 		}
123 
124 		@Override
getStorageVersion()125 		public int getStorageVersion() {
126 			return 0;
127 		}
128 
129 		@Override
createStorageHook(Generation generation)130 		protected TestStorageHook createStorageHook(Generation generation) {
131 			createStorageHookCalled = true;
132 			if (returnNullStorageHook) {
133 				return null;
134 			}
135 			Class<?> factoryClass = TestStorageHookFactory.class;
136 			if (invalidFactoryClass)
137 				factoryClass = StorageHookFactory.class;
138 			return new TestStorageHook(generation, factoryClass);
139 		}
140 
141 		@Override
handleContentConnection(Module module, String location, InputStream in)142 		public URLConnection handleContentConnection(Module module, String location, InputStream in) throws IOException {
143 			if (handleContentConnection) {
144 				final ByteArrayOutputStream baos = new ByteArrayOutputStream();
145 				Manifest manifest = new Manifest();
146 				Attributes attrs = manifest.getMainAttributes();
147 				attrs.putValue("Manifest-Version", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$
148 				attrs.putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
149 				attrs.putValue(Constants.BUNDLE_SYMBOLICNAME, "testHandleContentConnection");
150 				JarOutputStream jos = new JarOutputStream(baos, manifest);
151 				jos.close();
152 				return new URLConnection(null) {
153 					@Override
154 					public void connect() {
155 						connected = true;
156 					}
157 
158 					@Override
159 					public InputStream getInputStream() {
160 						return new ByteArrayInputStream(baos.toByteArray());
161 					}
162 				};
163 			}
164 			return super.handleContentConnection(module, location, in);
165 		}
166 	}
167 
168 	public static volatile boolean createStorageHookCalled;
169 	public static volatile boolean invalid;
170 	public static volatile boolean failLoad;
171 	public static volatile boolean invalidFactoryClass;
172 	public static volatile boolean validateCalled;
173 	public static volatile boolean deletingGenerationCalled;
174 	public static volatile boolean adaptManifest;
175 	public static volatile boolean adaptCapabilityAttribute;
176 	public static volatile boolean replaceModuleBuilder;
177 	public static volatile boolean handleContentConnection;
178 	public static volatile boolean returnNullStorageHook;
179 
180 	public void addHooks(HookRegistry hookRegistry) {
181 		hookRegistry.addStorageHookFactory(new TestStorageHookFactory());
182 		hookRegistry.addActivatorHookFactory(new ActivatorHookFactory() {
183 
184 			@Override
185 			public BundleActivator createActivator() {
186 				return new BundleActivator() {
187 
188 					@Override
189 					public void start(BundleContext context) throws Exception {
190 						TestHelper.testBundle = context.getBundle(Constants.SYSTEM_BUNDLE_LOCATION);
191 					}
192 
193 					@Override
194 					public void stop(BundleContext context) throws Exception {
195 						// nothing
196 					}
197 				};
198 			}
199 		});
200 	}
201 }
202