View Javadoc
1   package org.argeo.osgi.a2;
2   
3   import java.io.File;
4   import java.net.URI;
5   import java.nio.file.Files;
6   import java.nio.file.Path;
7   import java.nio.file.Paths;
8   import java.util.ArrayList;
9   import java.util.Collection;
10  import java.util.Collections;
11  import java.util.HashMap;
12  import java.util.HashSet;
13  import java.util.List;
14  import java.util.Map;
15  import java.util.Set;
16  
17  import org.argeo.osgi.boot.OsgiBootUtils;
18  import org.eclipse.osgi.launch.EquinoxFactory;
19  import org.osgi.framework.Bundle;
20  import org.osgi.framework.BundleContext;
21  import org.osgi.framework.Constants;
22  import org.osgi.framework.Version;
23  import org.osgi.framework.launch.Framework;
24  import org.osgi.framework.wiring.FrameworkWiring;
25  
26  /** Loads provisioning sources into an OSGi context. */
27  public class ProvisioningManager {
28  	BundleContext bc;
29  	OsgiContext osgiContext;
30  	List<ProvisioningSource> sources = Collections.synchronizedList(new ArrayList<>());
31  
32  	public ProvisioningManager(BundleContext bc) {
33  		this.bc = bc;
34  		osgiContext = new OsgiContext(bc);
35  		osgiContext.load();
36  	}
37  
38  	protected void addSource(ProvisioningSource source) {
39  		sources.add(source);
40  	}
41  
42  	void installWholeSource(ProvisioningSource source) {
43  		Set<Bundle> updatedBundles = new HashSet<>();
44  		for (A2Contribution contribution : source.listContributions(null)) {
45  			for (A2Component component : contribution.components.values()) {
46  				A2Module module = component.last().last();
47  				Bundle bundle = installOrUpdate(module);
48  				if (bundle != null)
49  					updatedBundles.add(bundle);
50  			}
51  		}
52  		FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
53  		frameworkWiring.refreshBundles(updatedBundles);
54  	}
55  
56  	public void registerSource(String uri) {
57  		try {
58  			URI u = new URI(uri);
59  			if (A2Source.SCHEME_A2.equals(u.getScheme())) {
60  				if (u.getHost() == null || "".equals(u.getHost())) {
61  					String baseStr = u.getPath();
62  					if (File.separatorChar == '\\') {// MS Windows
63  						baseStr = baseStr.substring(1).replace('/', File.separatorChar);
64  					}
65  					Path base = Paths.get(baseStr);
66  					if (Files.exists(base)) {
67  						FsA2Source source = new FsA2Source(base);
68  						source.load();
69  						addSource(source);
70  						OsgiBootUtils.info("Registered " + uri + " as source");
71  					}
72  				}
73  			}
74  		} catch (Exception e) {
75  			throw new A2Exception("Cannot add source " + uri, e);
76  		}
77  	}
78  
79  	public boolean registerDefaultSource() {
80  		String frameworkLocation = bc.getProperty("osgi.framework");
81  		try {
82  			URI frameworkLocationUri = new URI(frameworkLocation);
83  			if ("file".equals(frameworkLocationUri.getScheme())) {
84  				Path frameworkPath = Paths.get(frameworkLocationUri);
85  				if (frameworkPath.getParent().getFileName().toString().equals(A2Contribution.BOOT)) {
86  					Path base = frameworkPath.getParent().getParent();
87  					String baseStr = base.toString();
88  					if (File.separatorChar == '\\')// MS Windows
89  						baseStr = '/' + baseStr.replace(File.separatorChar, '/');
90  					URI baseUri = new URI(A2Source.SCHEME_A2, null, null, 0, baseStr, null, null);
91  					registerSource(baseUri.toString());
92  					OsgiBootUtils.debug("Default source from framework location " + frameworkLocation);
93  					return true;
94  				}
95  			}
96  		} catch (Exception e) {
97  			OsgiBootUtils.error("Cannot register default source based on framework location " + frameworkLocation, e);
98  		}
99  		return false;
100 	}
101 
102 	public void install(String spec) {
103 		if (spec == null) {
104 			for (ProvisioningSource source : sources) {
105 				installWholeSource(source);
106 			}
107 		}
108 	}
109 
110 	/** @return the new/updated bundle, or null if nothing was done. */
111 	protected Bundle installOrUpdate(A2Module module) {
112 		try {
113 			ProvisioningSource moduleSource = module.getBranch().getComponent().getContribution().getSource();
114 			Version moduleVersion = module.getVersion();
115 			A2Branch osgiBranch = osgiContext.findBranch(module.getBranch().getComponent().getId(), moduleVersion);
116 			if (osgiBranch == null) {
117 //				Bundle bundle = bc.installBundle(module.getBranch().getCoordinates(),
118 //						moduleSource.newInputStream(module.getLocator()));
119 				Bundle bundle = moduleSource.install(bc, module);
120 				if (OsgiBootUtils.isDebug())
121 					OsgiBootUtils.debug("Installed bundle " + bundle.getLocation() + " with version " + moduleVersion);
122 				return bundle;
123 			} else {
124 				A2Module lastOsgiModule = osgiBranch.last();
125 				int compare = moduleVersion.compareTo(lastOsgiModule.getVersion());
126 				if (compare > 0) {// update
127 					Bundle bundle = (Bundle) lastOsgiModule.getLocator();
128 //					bundle.update(moduleSource.newInputStream(module.getLocator()));
129 					moduleSource.update(bundle, module);
130 					OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
131 					return bundle;
132 				}
133 			}
134 		} catch (Exception e) {
135 			OsgiBootUtils.error("Could not install module " + module + ": " + e.getMessage(), e);
136 		}
137 		return null;
138 	}
139 
140 	public Collection<Bundle> update() {
141 		boolean fragmentsUpdated = false;
142 		Set<Bundle> updatedBundles = new HashSet<>();
143 		bundles: for (Bundle bundle : bc.getBundles()) {
144 			for (ProvisioningSource source : sources) {
145 				String componentId = bundle.getSymbolicName();
146 				Version version = bundle.getVersion();
147 				A2Branch branch = source.findBranch(componentId, version);
148 				if (branch == null)
149 					continue bundles;
150 				A2Module module = branch.last();
151 				Version moduleVersion = module.getVersion();
152 				int compare = moduleVersion.compareTo(version);
153 				if (compare > 0) {// update
154 					try {
155 						source.update(bundle, module);
156 //						bundle.update(in);
157 						String fragmentHost = bundle.getHeaders().get(Constants.FRAGMENT_HOST);
158 						if (fragmentHost != null)
159 							fragmentsUpdated = true;
160 						OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
161 						updatedBundles.add(bundle);
162 					} catch (Exception e) {
163 						OsgiBootUtils.error("Cannot update with module " + module, e);
164 					}
165 				}
166 			}
167 		}
168 		FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
169 		if (fragmentsUpdated)// refresh all
170 			frameworkWiring.refreshBundles(null);
171 		else
172 			frameworkWiring.refreshBundles(updatedBundles);
173 		return updatedBundles;
174 	}
175 
176 	public static void main(String[] args) {
177 		Map<String, String> configuration = new HashMap<>();
178 		configuration.put("osgi.console", "2323");
179 		Framework framework = OsgiBootUtils.launch(new EquinoxFactory(), configuration);
180 		try {
181 			ProvisioningManager pm = new ProvisioningManager(framework.getBundleContext());
182 			FsA2Source context = new FsA2Source(Paths.get(
183 					"/home/mbaudier/dev/git/apache2/argeo-commons/dist/argeo-node/target/argeo-node-2.1.74-SNAPSHOT/argeo-node/share/osgi"));
184 			context.load();
185 			if (framework.getBundleContext().getBundles().length == 1) {// initial
186 				pm.install(null);
187 			} else {
188 				pm.update();
189 			}
190 		} catch (Exception e) {
191 			e.printStackTrace();
192 		} finally {
193 			try {
194 				// framework.stop();
195 			} catch (Exception e) {
196 				e.printStackTrace();
197 			}
198 		}
199 	}
200 
201 }