Richard S. Hall | 5ace92e | 2006-09-21 20:37:54 +0000 | [diff] [blame] | 1 | /* |
Richard S. Hall | b395167 | 2006-09-19 17:04:53 +0000 | [diff] [blame] | 2 | * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | * or more contributor license agreements. See the NOTICE file |
| 4 | * distributed with this work for additional information |
| 5 | * regarding copyright ownership. The ASF licenses this file |
| 6 | * to you under the Apache License, Version 2.0 (the |
| 7 | * "License"); you may not use this file except in compliance |
| 8 | * with the License. You may obtain a copy of the License at |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 9 | * |
Richard S. Hall | b395167 | 2006-09-19 17:04:53 +0000 | [diff] [blame] | 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 11 | * |
Richard S. Hall | b395167 | 2006-09-19 17:04:53 +0000 | [diff] [blame] | 12 | * Unless required by applicable law or agreed to in writing, |
| 13 | * software distributed under the License is distributed on an |
| 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | * KIND, either express or implied. See the License for the |
| 16 | * specific language governing permissions and limitations |
| 17 | * under the License. |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 18 | */ |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 19 | package org.apache.felix.framework.util.manifestparser; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 20 | |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 21 | import java.util.*; |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 22 | import java.util.ArrayList; |
| 23 | import java.util.Map.Entry; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 24 | import org.apache.felix.framework.BundleRevisionImpl; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 25 | |
| 26 | import org.apache.felix.framework.Logger; |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 27 | import org.apache.felix.framework.capabilityset.SimpleFilter; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 28 | import org.apache.felix.framework.wiring.BundleCapabilityImpl; |
Carsten Ziegeler | fc8029a | 2008-05-14 16:26:03 +0000 | [diff] [blame] | 29 | import org.apache.felix.framework.util.FelixConstants; |
| 30 | import org.apache.felix.framework.util.VersionRange; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 31 | import org.apache.felix.framework.wiring.BundleRequirementImpl; |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 32 | import org.osgi.framework.BundleException; |
| 33 | import org.osgi.framework.Constants; |
| 34 | import org.osgi.framework.Version; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 35 | import org.osgi.framework.wiring.BundleCapability; |
| 36 | import org.osgi.framework.wiring.BundleRequirement; |
| 37 | import org.osgi.framework.wiring.BundleRevision; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 38 | |
| 39 | public class ManifestParser |
| 40 | { |
Karl Pauls | 7129443 | 2009-03-16 23:34:01 +0000 | [diff] [blame] | 41 | private final Logger m_logger; |
| 42 | private final Map m_configMap; |
| 43 | private final Map m_headerMap; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 44 | private volatile int m_activationPolicy = BundleRevisionImpl.EAGER_ACTIVATION; |
Richard S. Hall | 10d9d2c | 2009-06-12 20:21:59 +0000 | [diff] [blame] | 45 | private volatile String m_activationIncludeDir; |
| 46 | private volatile String m_activationExcludeDir; |
Karl Pauls | 7129443 | 2009-03-16 23:34:01 +0000 | [diff] [blame] | 47 | private volatile boolean m_isExtension = false; |
| 48 | private volatile String m_bundleSymbolicName; |
| 49 | private volatile Version m_bundleVersion; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 50 | private volatile List<BundleCapability> m_capabilities; |
| 51 | private volatile List<BundleRequirement> m_requirements; |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 52 | private volatile List<R4LibraryClause> m_libraryClauses; |
Karl Pauls | 7129443 | 2009-03-16 23:34:01 +0000 | [diff] [blame] | 53 | private volatile boolean m_libraryHeadersOptional = false; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 54 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 55 | public ManifestParser(Logger logger, Map configMap, BundleRevision owner, Map headerMap) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 56 | throws BundleException |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 57 | { |
| 58 | m_logger = logger; |
Richard S. Hall | 471e3e6 | 2007-07-11 19:25:33 +0000 | [diff] [blame] | 59 | m_configMap = configMap; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 60 | m_headerMap = headerMap; |
| 61 | |
| 62 | // Verify that only manifest version 2 is specified. |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 63 | String manifestVersion = getManifestVersion(m_headerMap); |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 64 | if ((manifestVersion != null) && !manifestVersion.equals("2")) |
| 65 | { |
| 66 | throw new BundleException( |
| 67 | "Unknown 'Bundle-ManifestVersion' value: " + manifestVersion); |
| 68 | } |
| 69 | |
Richard S. Hall | 9d4dcb0 | 2009-07-30 16:00:39 +0000 | [diff] [blame] | 70 | // Create lists to hold capabilities and requirements. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 71 | List<BundleCapabilityImpl> capList = new ArrayList(); |
Richard S. Hall | 4151e90 | 2006-12-27 16:11:16 +0000 | [diff] [blame] | 72 | |
| 73 | // |
Richard S. Hall | 7561a37 | 2009-01-27 19:34:12 +0000 | [diff] [blame] | 74 | // Parse bundle version. |
| 75 | // |
| 76 | |
| 77 | m_bundleVersion = Version.emptyVersion; |
| 78 | if (headerMap.get(Constants.BUNDLE_VERSION) != null) |
| 79 | { |
| 80 | try |
| 81 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 82 | m_bundleVersion = Version.parseVersion( |
| 83 | (String) headerMap.get(Constants.BUNDLE_VERSION)); |
Richard S. Hall | 7561a37 | 2009-01-27 19:34:12 +0000 | [diff] [blame] | 84 | } |
| 85 | catch (RuntimeException ex) |
| 86 | { |
| 87 | // R4 bundle versions must parse, R3 bundle version may not. |
Richard S. Hall | 0a239a3 | 2009-01-29 22:21:19 +0000 | [diff] [blame] | 88 | if (getManifestVersion().equals("2")) |
Richard S. Hall | 7561a37 | 2009-01-27 19:34:12 +0000 | [diff] [blame] | 89 | { |
| 90 | throw ex; |
| 91 | } |
| 92 | m_bundleVersion = Version.emptyVersion; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | // |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 97 | // Parse bundle symbolic name. |
| 98 | // |
| 99 | |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 100 | BundleCapabilityImpl bundleCap = parseBundleSymbolicName(owner, m_headerMap); |
| 101 | if (bundleCap != null) |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 102 | { |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 103 | m_bundleSymbolicName = (String) |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 104 | bundleCap.getAttributes().get(BundleRevision.BUNDLE_NAMESPACE); |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 105 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 106 | // Add a bundle capability and a host capability to all |
Richard S. Hall | 5dc4bb7 | 2009-05-05 15:09:28 +0000 | [diff] [blame] | 107 | // non-fragment bundles. A host capability is the same |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 108 | // as a require capability, but with a different capability |
| 109 | // namespace. Bundle capabilities resolve required-bundle |
Richard S. Hall | 5dc4bb7 | 2009-05-05 15:09:28 +0000 | [diff] [blame] | 110 | // dependencies, while host capabilities resolve fragment-host |
| 111 | // dependencies. |
Richard S. Hall | 2846a2b | 2008-06-01 03:08:17 +0000 | [diff] [blame] | 112 | if (headerMap.get(Constants.FRAGMENT_HOST) == null) |
| 113 | { |
Richard S. Hall | 577b2c9 | 2011-06-20 16:29:53 +0000 | [diff] [blame] | 114 | // All non-fragment bundles have host capabilities. |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 115 | capList.add(bundleCap); |
Richard S. Hall | 577b2c9 | 2011-06-20 16:29:53 +0000 | [diff] [blame] | 116 | // A non-fragment bundle can choose to not have a host capability. |
| 117 | String attachment = |
| 118 | bundleCap.getDirectives().get(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE); |
| 119 | attachment = (attachment == null) |
| 120 | ? Constants.FRAGMENT_ATTACHMENT_RESOLVETIME |
| 121 | : attachment; |
| 122 | if (!attachment.equalsIgnoreCase(Constants.FRAGMENT_ATTACHMENT_NEVER)) |
| 123 | { |
| 124 | Map<String, Object> hostAttrs = |
| 125 | new HashMap<String, Object>(bundleCap.getAttributes()); |
| 126 | Object value = hostAttrs.remove(BundleRevision.BUNDLE_NAMESPACE); |
| 127 | hostAttrs.put(BundleRevision.HOST_NAMESPACE, value); |
| 128 | capList.add(new BundleCapabilityImpl( |
| 129 | owner, BundleRevision.HOST_NAMESPACE, |
| 130 | Collections.EMPTY_MAP, |
| 131 | hostAttrs)); |
| 132 | } |
Richard S. Hall | 2846a2b | 2008-06-01 03:08:17 +0000 | [diff] [blame] | 133 | } |
Richard S. Hall | da7b75e | 2011-03-04 21:27:59 +0000 | [diff] [blame] | 134 | |
| 135 | // Add a singleton capability if the bundle is a singleton. |
| 136 | // This is sort of a hack, but we need this for the resolver |
| 137 | // to be able to resolve singletons. It is not possible to |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 138 | // attach this information to the bundle or host capabilities |
Richard S. Hall | da7b75e | 2011-03-04 21:27:59 +0000 | [diff] [blame] | 139 | // because fragments don't have those capabilities, but fragments |
| 140 | // can be singletons too. |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 141 | if (isSingleton(bundleCap)) |
Richard S. Hall | da7b75e | 2011-03-04 21:27:59 +0000 | [diff] [blame] | 142 | { |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 143 | Map<String, Object> singletonAttrs = |
| 144 | new HashMap<String, Object>(bundleCap.getAttributes()); |
| 145 | Object value = singletonAttrs.remove(BundleRevision.BUNDLE_NAMESPACE); |
| 146 | singletonAttrs.put(BundleCapabilityImpl.SINGLETON_NAMESPACE, value); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 147 | capList.add(new BundleCapabilityImpl( |
| 148 | owner, BundleCapabilityImpl.SINGLETON_NAMESPACE, |
| 149 | Collections.EMPTY_MAP, |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 150 | singletonAttrs)); |
Richard S. Hall | da7b75e | 2011-03-04 21:27:59 +0000 | [diff] [blame] | 151 | } |
Richard S. Hall | 2846a2b | 2008-06-01 03:08:17 +0000 | [diff] [blame] | 152 | } |
| 153 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 154 | // Verify that bundle symbolic name is specified. |
| 155 | if (getManifestVersion().equals("2") && (m_bundleSymbolicName == null)) |
| 156 | { |
| 157 | throw new BundleException( |
| 158 | "R4 bundle manifests must include bundle symbolic name."); |
| 159 | } |
| 160 | |
| 161 | // |
| 162 | // Parse Fragment-Host. |
| 163 | // |
| 164 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 165 | List<BundleRequirementImpl> hostReqs = parseFragmentHost(m_logger, owner, m_headerMap); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 166 | |
| 167 | // |
| 168 | // Parse Require-Bundle |
| 169 | // |
| 170 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 171 | List<ParsedHeaderClause> rbClauses = |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 172 | parseStandardHeader((String) headerMap.get(Constants.REQUIRE_BUNDLE)); |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 173 | rbClauses = normalizeRequireClauses(m_logger, rbClauses, getManifestVersion()); |
| 174 | List<BundleRequirementImpl> rbReqs = convertRequires(rbClauses, owner); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 175 | |
| 176 | // |
| 177 | // Parse Import-Package. |
| 178 | // |
| 179 | |
| 180 | List<ParsedHeaderClause> importClauses = |
| 181 | parseStandardHeader((String) headerMap.get(Constants.IMPORT_PACKAGE)); |
| 182 | importClauses = normalizeImportClauses(m_logger, importClauses, getManifestVersion()); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 183 | List<BundleRequirement> importReqs = convertImports(importClauses, owner); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 184 | |
| 185 | // |
| 186 | // Parse DynamicImport-Package. |
| 187 | // |
| 188 | |
| 189 | List<ParsedHeaderClause> dynamicClauses = |
| 190 | parseStandardHeader((String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE)); |
| 191 | dynamicClauses = normalizeDynamicImportClauses(m_logger, dynamicClauses, getManifestVersion()); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 192 | List<BundleRequirement> dynamicReqs = convertImports(dynamicClauses, owner); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 193 | |
Richard S. Hall | 2846a2b | 2008-06-01 03:08:17 +0000 | [diff] [blame] | 194 | // |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 195 | // Parse Require-Capability. |
| 196 | // |
| 197 | |
| 198 | List<ParsedHeaderClause> requireClauses = |
| 199 | parseStandardHeader((String) headerMap.get(Constants.REQUIRE_CAPABILITY)); |
| 200 | importClauses = normalizeRequireCapabilityClauses( |
| 201 | m_logger, requireClauses, getManifestVersion()); |
| 202 | List<BundleRequirement> requireReqs = convertRequireCapabilities(importClauses, owner); |
| 203 | |
| 204 | // |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 205 | // Parse Export-Package. |
| 206 | // |
| 207 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 208 | List<ParsedHeaderClause> exportClauses = |
| 209 | parseStandardHeader((String) headerMap.get(Constants.EXPORT_PACKAGE)); |
| 210 | exportClauses = normalizeExportClauses(logger, exportClauses, |
| 211 | getManifestVersion(), m_bundleSymbolicName, m_bundleVersion); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 212 | List<BundleCapability> exportCaps = convertExports(exportClauses, owner); |
Richard S. Hall | 7baf7b8 | 2007-01-31 21:11:11 +0000 | [diff] [blame] | 213 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 214 | // |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 215 | // Parse Provide-Capability. |
| 216 | // |
| 217 | |
| 218 | List<ParsedHeaderClause> provideClauses = |
| 219 | parseStandardHeader((String) headerMap.get(Constants.PROVIDE_CAPABILITY)); |
| 220 | exportClauses = normalizeProvideCapabilityClauses( |
| 221 | logger, provideClauses, getManifestVersion()); |
| 222 | List<BundleCapability> provideCaps = convertProvideCapabilities(provideClauses, owner); |
| 223 | |
| 224 | // |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 225 | // Calculate implicit imports. |
| 226 | // |
| 227 | |
| 228 | if (!getManifestVersion().equals("2")) |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 229 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 230 | List<ParsedHeaderClause> implicitClauses = |
| 231 | calculateImplicitImports(exportCaps, importClauses); |
Richard S. Hall | 1a879e5 | 2010-04-18 19:22:48 +0000 | [diff] [blame] | 232 | importReqs.addAll(convertImports(implicitClauses, owner)); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 233 | |
| 234 | List<ParsedHeaderClause> allImportClauses = |
| 235 | new ArrayList<ParsedHeaderClause>(implicitClauses.size() + importClauses.size()); |
| 236 | allImportClauses.addAll(importClauses); |
| 237 | allImportClauses.addAll(implicitClauses); |
| 238 | |
| 239 | exportCaps = calculateImplicitUses(exportCaps, allImportClauses); |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 240 | } |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 241 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 242 | // Combine all capabilities. |
| 243 | m_capabilities = new ArrayList( |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 244 | capList.size() + exportCaps.size() + provideCaps.size()); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 245 | m_capabilities.addAll(capList); |
| 246 | m_capabilities.addAll(exportCaps); |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 247 | m_capabilities.addAll(provideCaps); |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 248 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 249 | // Combine all requirements. |
| 250 | m_requirements = new ArrayList( |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 251 | importReqs.size() + rbReqs.size() + hostReqs.size() |
| 252 | + requireReqs.size() + dynamicReqs.size()); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 253 | m_requirements.addAll(importReqs); |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 254 | m_requirements.addAll(rbReqs); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 255 | m_requirements.addAll(hostReqs); |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 256 | m_requirements.addAll(requireReqs); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 257 | m_requirements.addAll(dynamicReqs); |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 258 | |
| 259 | // |
| 260 | // Parse Bundle-NativeCode. |
| 261 | // |
| 262 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 263 | // Parse native library clauses. |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 264 | m_libraryClauses = |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 265 | parseLibraryStrings( |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 266 | m_logger, |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 267 | parseDelimitedString((String) m_headerMap.get(Constants.BUNDLE_NATIVECODE), ",")); |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 268 | |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 269 | // Check to see if there was an optional native library clause, which is |
| 270 | // represented by a null library header; if so, record it and remove it. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 271 | if (!m_libraryClauses.isEmpty() && |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 272 | (m_libraryClauses.get(m_libraryClauses.size() - 1).getLibraryEntries() == null)) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 273 | { |
| 274 | m_libraryHeadersOptional = true; |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 275 | m_libraryClauses.remove(m_libraryClauses.size() - 1); |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 276 | } |
| 277 | |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 278 | // |
| 279 | // Parse activation policy. |
| 280 | // |
| 281 | |
Richard S. Hall | 10d9d2c | 2009-06-12 20:21:59 +0000 | [diff] [blame] | 282 | // This sets m_activationPolicy, m_includedPolicyClasses, and |
| 283 | // m_excludedPolicyClasses. |
| 284 | parseActivationPolicy(headerMap); |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 285 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 286 | m_isExtension = checkExtensionBundle(headerMap); |
| 287 | } |
| 288 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 289 | private static boolean isSingleton(BundleCapabilityImpl cap) |
Richard S. Hall | da7b75e | 2011-03-04 21:27:59 +0000 | [diff] [blame] | 290 | { |
Richard S. Hall | 2c0bf6b | 2011-06-07 18:00:08 +0000 | [diff] [blame] | 291 | if (cap.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE)) |
Richard S. Hall | da7b75e | 2011-03-04 21:27:59 +0000 | [diff] [blame] | 292 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 293 | String value = cap.getDirectives().get(Constants.SINGLETON_DIRECTIVE); |
| 294 | if ((value != null) && Boolean.valueOf(value)) |
Richard S. Hall | da7b75e | 2011-03-04 21:27:59 +0000 | [diff] [blame] | 295 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 296 | return true; |
Richard S. Hall | da7b75e | 2011-03-04 21:27:59 +0000 | [diff] [blame] | 297 | } |
| 298 | } |
| 299 | return false; |
| 300 | } |
| 301 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 302 | private static List<ParsedHeaderClause> normalizeImportClauses( |
| 303 | Logger logger, List<ParsedHeaderClause> clauses, String mv) |
| 304 | throws BundleException |
| 305 | { |
| 306 | // Verify that the values are equals if the package specifies |
| 307 | // both version and specification-version attributes. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 308 | Set dupeSet = new HashSet(); |
| 309 | for (ParsedHeaderClause clause : clauses) |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 310 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 311 | // Check for "version" and "specification-version" attributes |
| 312 | // and verify they are the same if both are specified. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 313 | Object v = clause.m_attrs.get(Constants.VERSION_ATTRIBUTE); |
| 314 | Object sv = clause.m_attrs.get(Constants.PACKAGE_SPECIFICATION_VERSION); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 315 | if ((v != null) && (sv != null)) |
| 316 | { |
| 317 | // Verify they are equal. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 318 | if (!((String) v).trim().equals(((String) sv).trim())) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 319 | { |
| 320 | throw new IllegalArgumentException( |
| 321 | "Both version and specification-version are specified, but they are not equal."); |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | // Ensure that only the "version" attribute is used and convert |
| 326 | // it to the VersionRange type. |
| 327 | if ((v != null) || (sv != null)) |
| 328 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 329 | clause.m_attrs.remove(Constants.PACKAGE_SPECIFICATION_VERSION); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 330 | v = (v == null) ? sv : v; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 331 | clause.m_attrs.put( |
| 332 | Constants.VERSION_ATTRIBUTE, |
| 333 | VersionRange.parse(v.toString())); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 334 | } |
| 335 | |
| 336 | // If bundle version is specified, then convert its type to VersionRange. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 337 | v = clause.m_attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 338 | if (v != null) |
| 339 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 340 | clause.m_attrs.put( |
| 341 | Constants.BUNDLE_VERSION_ATTRIBUTE, |
| 342 | VersionRange.parse(v.toString())); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 343 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 344 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 345 | // Verify java.* is not imported, nor any duplicate imports. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 346 | for (String pkgName : clause.m_paths) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 347 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 348 | if (!dupeSet.contains(pkgName)) |
| 349 | { |
| 350 | // Verify that java.* packages are not imported. |
| 351 | if (pkgName.startsWith("java.")) |
| 352 | { |
| 353 | throw new BundleException( |
| 354 | "Importing java.* packages not allowed: " + pkgName); |
| 355 | } |
| 356 | // Make sure a package name was specified. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 357 | else if (pkgName.length() == 0) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 358 | { |
| 359 | throw new BundleException( |
| 360 | "Imported package names cannot be zero length."); |
| 361 | } |
| 362 | dupeSet.add(pkgName); |
| 363 | } |
| 364 | else |
| 365 | { |
| 366 | throw new BundleException("Duplicate import: " + pkgName); |
| 367 | } |
| 368 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 369 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 370 | if (!mv.equals("2")) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 371 | { |
| 372 | // R3 bundles cannot have directives on their imports. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 373 | if (!clause.m_dirs.isEmpty()) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 374 | { |
| 375 | throw new BundleException("R3 imports cannot contain directives."); |
| 376 | } |
| 377 | |
| 378 | // Remove and ignore all attributes other than version. |
| 379 | // NOTE: This is checking for "version" rather than "specification-version" |
| 380 | // because the package class normalizes to "version" to avoid having |
| 381 | // future special cases. This could be changed if more strict behavior |
| 382 | // is required. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 383 | if (!clause.m_attrs.isEmpty()) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 384 | { |
| 385 | // R3 package requirements should only have version attributes. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 386 | Object pkgVersion = clause.m_attrs.get(BundleCapabilityImpl.VERSION_ATTR); |
| 387 | pkgVersion = (pkgVersion == null) |
| 388 | ? new VersionRange(Version.emptyVersion, true, null, true) |
| 389 | : pkgVersion; |
| 390 | for (Entry<String, Object> entry : clause.m_attrs.entrySet()) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 391 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 392 | if (!entry.getKey().equals(BundleCapabilityImpl.VERSION_ATTR)) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 393 | { |
| 394 | logger.log(Logger.LOG_WARNING, |
| 395 | "Unknown R3 import attribute: " |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 396 | + entry.getKey()); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 397 | } |
| 398 | } |
| 399 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 400 | // Remove all other attributes except package version. |
| 401 | clause.m_attrs.clear(); |
| 402 | clause.m_attrs.put(BundleCapabilityImpl.VERSION_ATTR, pkgVersion); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 403 | } |
| 404 | } |
| 405 | } |
| 406 | |
| 407 | return clauses; |
| 408 | } |
| 409 | |
Richard S. Hall | 7eb28b9 | 2011-05-24 17:23:15 +0000 | [diff] [blame] | 410 | public static List<BundleRequirement> parseDynamicImportHeader( |
| 411 | Logger logger, BundleRevision owner, String header) |
| 412 | throws BundleException |
| 413 | { |
| 414 | |
| 415 | List<ParsedHeaderClause> importClauses = parseStandardHeader(header); |
| 416 | importClauses = normalizeDynamicImportClauses(logger, importClauses, "2"); |
| 417 | List<BundleRequirement> reqs = convertImports(importClauses, owner); |
| 418 | return reqs; |
| 419 | } |
| 420 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 421 | private static List<BundleRequirement> convertImports( |
| 422 | List<ParsedHeaderClause> clauses, BundleRevision owner) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 423 | { |
| 424 | // Now convert generic header clauses into requirements. |
| 425 | List reqList = new ArrayList(); |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 426 | for (ParsedHeaderClause clause : clauses) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 427 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 428 | for (String path : clause.m_paths) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 429 | { |
| 430 | // Prepend the package name to the array of attributes. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 431 | Map<String, Object> attrs = clause.m_attrs; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 432 | // Note that we use a linked hash map here to ensure the |
| 433 | // package attribute is first, which will make indexing |
| 434 | // more efficient. |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 435 | // TODO: OSGi R4.3 - This ordering fix is a hack...perhaps we should use the standard "key" |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 436 | // notion where namespace is also the name of the key attribute. |
| 437 | Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1); |
| 438 | newAttrs.put( |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 439 | BundleRevision.PACKAGE_NAMESPACE, |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 440 | path); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 441 | newAttrs.putAll(attrs); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 442 | |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 443 | // Create filter now so we can inject filter directive. |
| 444 | SimpleFilter sf = BundleRequirementImpl.convertToFilter(newAttrs); |
| 445 | |
| 446 | // Inject filter directive. |
| 447 | // TODO: OSGi R4.3 - Can we insert this on demand somehow? |
| 448 | Map<String, String> dirs = clause.m_dirs; |
| 449 | Map<String, String> newDirs = new HashMap<String, String>(dirs.size() + 1); |
| 450 | newDirs.putAll(dirs); |
| 451 | newDirs.put( |
| 452 | Constants.FILTER_DIRECTIVE, |
| 453 | sf.toString()); |
| 454 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 455 | // Create package requirement and add to requirement list. |
| 456 | reqList.add( |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 457 | new BundleRequirementImpl( |
Richard S. Hall | 1a879e5 | 2010-04-18 19:22:48 +0000 | [diff] [blame] | 458 | owner, |
Richard S. Hall | 2c0bf6b | 2011-06-07 18:00:08 +0000 | [diff] [blame] | 459 | BundleRevision.PACKAGE_NAMESPACE, |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 460 | newDirs, |
| 461 | Collections.EMPTY_MAP, |
| 462 | sf)); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 463 | } |
| 464 | } |
| 465 | |
| 466 | return reqList; |
| 467 | } |
| 468 | |
| 469 | private static List<ParsedHeaderClause> normalizeDynamicImportClauses( |
| 470 | Logger logger, List<ParsedHeaderClause> clauses, String mv) |
| 471 | throws BundleException |
| 472 | { |
| 473 | // Verify that the values are equals if the package specifies |
| 474 | // both version and specification-version attributes. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 475 | for (ParsedHeaderClause clause : clauses) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 476 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 477 | if (!mv.equals("2")) |
Richard S. Hall | 66ee2e6 | 2011-05-13 18:11:41 +0000 | [diff] [blame] | 478 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 479 | // R3 bundles cannot have directives on their imports. |
| 480 | if (!clause.m_dirs.isEmpty()) |
| 481 | { |
| 482 | throw new BundleException("R3 imports cannot contain directives."); |
| 483 | } |
Richard S. Hall | 66ee2e6 | 2011-05-13 18:11:41 +0000 | [diff] [blame] | 484 | } |
| 485 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 486 | // Add the resolution directive to indicate that these are |
| 487 | // dynamic imports. |
| 488 | // TODO: OSGi R4.3 - Use real constant value for "dynamic". |
| 489 | clause.m_dirs.put(Constants.RESOLUTION_DIRECTIVE, "dynamic"); |
| 490 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 491 | // Check for "version" and "specification-version" attributes |
| 492 | // and verify they are the same if both are specified. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 493 | Object v = clause.m_attrs.get(Constants.VERSION_ATTRIBUTE); |
| 494 | Object sv = clause.m_attrs.get(Constants.PACKAGE_SPECIFICATION_VERSION); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 495 | if ((v != null) && (sv != null)) |
| 496 | { |
| 497 | // Verify they are equal. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 498 | if (!((String) v).trim().equals(((String) sv).trim())) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 499 | { |
| 500 | throw new IllegalArgumentException( |
| 501 | "Both version and specification-version are specified, but they are not equal."); |
| 502 | } |
| 503 | } |
| 504 | |
| 505 | // Ensure that only the "version" attribute is used and convert |
| 506 | // it to the VersionRange type. |
| 507 | if ((v != null) || (sv != null)) |
| 508 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 509 | clause.m_attrs.remove(Constants.PACKAGE_SPECIFICATION_VERSION); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 510 | v = (v == null) ? sv : v; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 511 | clause.m_attrs.put( |
| 512 | Constants.VERSION_ATTRIBUTE, |
| 513 | VersionRange.parse(v.toString())); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 514 | } |
| 515 | |
| 516 | // If bundle version is specified, then convert its type to VersionRange. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 517 | v = clause.m_attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 518 | if (v != null) |
| 519 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 520 | clause.m_attrs.put( |
| 521 | Constants.BUNDLE_VERSION_ATTRIBUTE, |
| 522 | VersionRange.parse(v.toString())); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 523 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 524 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 525 | // Dynamic imports can have duplicates, so verify that java.* |
| 526 | // packages are not imported. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 527 | for (String pkgName : clause.m_paths) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 528 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 529 | if (pkgName.startsWith("java.")) |
| 530 | { |
| 531 | throw new BundleException( |
| 532 | "Dynamically importing java.* packages not allowed: " + pkgName); |
| 533 | } |
| 534 | else if (!pkgName.equals("*") && pkgName.endsWith("*") && !pkgName.endsWith(".*")) |
| 535 | { |
| 536 | throw new BundleException( |
| 537 | "Partial package name wild carding is not allowed: " + pkgName); |
| 538 | } |
| 539 | } |
| 540 | } |
| 541 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 542 | return clauses; |
| 543 | } |
| 544 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 545 | private static List<ParsedHeaderClause> normalizeRequireCapabilityClauses( |
| 546 | Logger logger, List<ParsedHeaderClause> clauses, String mv) |
| 547 | throws BundleException |
| 548 | { |
| 549 | |
| 550 | if (!mv.equals("2") && !clauses.isEmpty()) |
| 551 | { |
| 552 | // Should we error here if we are not an R4 bundle? |
| 553 | } |
| 554 | |
| 555 | return clauses; |
| 556 | } |
| 557 | |
| 558 | private static List<BundleRequirement> convertRequireCapabilities( |
| 559 | List<ParsedHeaderClause> clauses, BundleRevision owner) |
| 560 | throws BundleException |
| 561 | { |
| 562 | // Now convert generic header clauses into requirements. |
| 563 | List reqList = new ArrayList(); |
| 564 | for (ParsedHeaderClause clause : clauses) |
| 565 | { |
| 566 | try |
| 567 | { |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 568 | String filterStr = clause.m_dirs.get(Constants.FILTER_DIRECTIVE); |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 569 | SimpleFilter sf = (filterStr != null) |
| 570 | ? SimpleFilter.parse(filterStr) |
| 571 | : new SimpleFilter(null, null, SimpleFilter.MATCH_ALL); |
| 572 | for (String path : clause.m_paths) |
| 573 | { |
| 574 | // Create requirement and add to requirement list. |
| 575 | reqList.add( |
| 576 | new BundleRequirementImpl( |
| 577 | owner, |
| 578 | path, |
| 579 | clause.m_dirs, |
| 580 | clause.m_attrs, |
| 581 | sf)); |
| 582 | } |
| 583 | } |
| 584 | catch (Exception ex) |
| 585 | { |
| 586 | throw new BundleException("Error creating requirement: " + ex); |
| 587 | } |
| 588 | } |
| 589 | |
| 590 | return reqList; |
| 591 | } |
| 592 | |
| 593 | private static List<ParsedHeaderClause> normalizeProvideCapabilityClauses( |
| 594 | Logger logger, List<ParsedHeaderClause> clauses, String mv) |
| 595 | throws BundleException |
| 596 | { |
| 597 | |
| 598 | if (!mv.equals("2") && !clauses.isEmpty()) |
| 599 | { |
| 600 | // Should we error here if we are not an R4 bundle? |
| 601 | } |
| 602 | |
| 603 | // Convert attributes into specified types. |
| 604 | for (ParsedHeaderClause clause : clauses) |
| 605 | { |
| 606 | for (Entry<String, String> entry : clause.m_types.entrySet()) |
| 607 | { |
| 608 | String type = entry.getValue(); |
| 609 | if (!type.equals("String")) |
| 610 | { |
| 611 | if (type.equals("Double")) |
| 612 | { |
| 613 | clause.m_attrs.put( |
| 614 | entry.getKey(), |
| 615 | new Double(clause.m_attrs.get(entry.getKey()).toString().trim())); |
| 616 | } |
| 617 | else if (type.equals("Version")) |
| 618 | { |
| 619 | clause.m_attrs.put( |
| 620 | entry.getKey(), |
| 621 | new Version(clause.m_attrs.get(entry.getKey()).toString().trim())); |
| 622 | } |
| 623 | else if (type.equals("Long")) |
| 624 | { |
| 625 | clause.m_attrs.put( |
| 626 | entry.getKey(), |
| 627 | new Long(clause.m_attrs.get(entry.getKey()).toString().trim())); |
| 628 | } |
| 629 | else if (type.startsWith("List")) |
| 630 | { |
| 631 | int startIdx = type.indexOf('<'); |
| 632 | int endIdx = type.indexOf('>'); |
| 633 | if (((startIdx > 0) && (endIdx <= startIdx)) |
| 634 | || ((startIdx < 0) && (endIdx > 0))) |
| 635 | { |
| 636 | throw new BundleException( |
| 637 | "Invalid Provide-Capability attribute list type for '" |
| 638 | + entry.getKey() |
| 639 | + "' : " |
| 640 | + type); |
| 641 | } |
| 642 | |
| 643 | String listType = "String"; |
| 644 | if (endIdx > startIdx) |
| 645 | { |
| 646 | listType = type.substring(startIdx + 1, endIdx).trim(); |
| 647 | } |
| 648 | |
| 649 | List<String> tokens = parseDelimitedString( |
| 650 | clause.m_attrs.get(entry.getKey()).toString(), ",", false); |
| 651 | List<Object> values = new ArrayList<Object>(tokens.size()); |
| 652 | for (String token : tokens) |
| 653 | { |
| 654 | if (listType.equals("String")) |
| 655 | { |
| 656 | values.add(token); |
| 657 | } |
| 658 | else if (listType.equals("Double")) |
| 659 | { |
| 660 | values.add(new Double(token.trim())); |
| 661 | } |
| 662 | else if (listType.equals("Version")) |
| 663 | { |
| 664 | values.add(new Version(token.trim())); |
| 665 | } |
| 666 | else if (listType.equals("Long")) |
| 667 | { |
| 668 | values.add(new Long(token.trim())); |
| 669 | } |
| 670 | else |
| 671 | { |
| 672 | throw new BundleException( |
| 673 | "Unknown Provide-Capability attribute list type for '" |
| 674 | + entry.getKey() |
| 675 | + "' : " |
| 676 | + type); |
| 677 | } |
| 678 | } |
| 679 | clause.m_attrs.put( |
| 680 | entry.getKey(), |
| 681 | values); |
| 682 | } |
| 683 | else |
| 684 | { |
| 685 | throw new BundleException( |
| 686 | "Unknown Provide-Capability attribute type for '" |
| 687 | + entry.getKey() |
| 688 | + "' : " |
| 689 | + type); |
| 690 | } |
| 691 | } |
| 692 | } |
| 693 | } |
| 694 | |
| 695 | return clauses; |
| 696 | } |
| 697 | |
| 698 | private static List<BundleCapability> convertProvideCapabilities( |
| 699 | List<ParsedHeaderClause> clauses, BundleRevision owner) |
| 700 | { |
| 701 | List<BundleCapability> capList = new ArrayList(); |
| 702 | for (ParsedHeaderClause clause : clauses) |
| 703 | { |
| 704 | for (String path : clause.m_paths) |
| 705 | { |
| 706 | // Create package capability and add to capability list. |
| 707 | capList.add( |
| 708 | new BundleCapabilityImpl( |
| 709 | owner, |
| 710 | path, |
| 711 | clause.m_dirs, |
| 712 | clause.m_attrs)); |
| 713 | } |
| 714 | } |
| 715 | |
| 716 | return capList; |
| 717 | } |
| 718 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 719 | private static List<ParsedHeaderClause> normalizeExportClauses( |
| 720 | Logger logger, List<ParsedHeaderClause> clauses, |
| 721 | String mv, String bsn, Version bv) |
| 722 | throws BundleException |
| 723 | { |
| 724 | // Verify that "java.*" packages are not exported. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 725 | for (ParsedHeaderClause clause : clauses) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 726 | { |
| 727 | // Verify that the named package has not already been declared. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 728 | for (String pkgName : clause.m_paths) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 729 | { |
| 730 | // Verify that java.* packages are not exported. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 731 | if (pkgName.startsWith("java.")) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 732 | { |
| 733 | throw new BundleException( |
| 734 | "Exporting java.* packages not allowed: " |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 735 | + pkgName); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 736 | } |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 737 | else if (pkgName.length() == 0) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 738 | { |
| 739 | throw new BundleException( |
| 740 | "Exported package names cannot be zero length."); |
| 741 | } |
| 742 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 743 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 744 | // Check for "version" and "specification-version" attributes |
| 745 | // and verify they are the same if both are specified. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 746 | Object v = clause.m_attrs.get(Constants.VERSION_ATTRIBUTE); |
| 747 | Object sv = clause.m_attrs.get(Constants.PACKAGE_SPECIFICATION_VERSION); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 748 | if ((v != null) && (sv != null)) |
| 749 | { |
| 750 | // Verify they are equal. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 751 | if (!((String) v).trim().equals(((String) sv).trim())) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 752 | { |
| 753 | throw new IllegalArgumentException( |
| 754 | "Both version and specification-version are specified, but they are not equal."); |
| 755 | } |
| 756 | } |
| 757 | |
| 758 | // Always add the default version if not specified. |
| 759 | if ((v == null) && (sv == null)) |
| 760 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 761 | v = Version.emptyVersion; |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 762 | } |
| 763 | |
| 764 | // Ensure that only the "version" attribute is used and convert |
| 765 | // it to the appropriate type. |
| 766 | if ((v != null) || (sv != null)) |
| 767 | { |
| 768 | // Convert version attribute to type Version. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 769 | clause.m_attrs.remove(Constants.PACKAGE_SPECIFICATION_VERSION); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 770 | v = (v == null) ? sv : v; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 771 | clause.m_attrs.put( |
| 772 | Constants.VERSION_ATTRIBUTE, |
| 773 | Version.parseVersion(v.toString())); |
Karl Pauls | 9dd2233 | 2011-05-16 21:49:02 +0000 | [diff] [blame] | 774 | } |
Karl Pauls | 9dd2233 | 2011-05-16 21:49:02 +0000 | [diff] [blame] | 775 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 776 | // If this is an R4 bundle, then make sure it doesn't specify |
| 777 | // bundle symbolic name or bundle version attributes. |
| 778 | if (mv.equals("2")) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 779 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 780 | // Find symbolic name and version attribute, if present. |
| 781 | if (clause.m_attrs.containsKey(Constants.BUNDLE_VERSION_ATTRIBUTE) |
| 782 | || clause.m_attrs.containsKey(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 783 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 784 | throw new BundleException( |
| 785 | "Exports must not specify bundle symbolic name or bundle version."); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 786 | } |
| 787 | |
| 788 | // Now that we know that there are no bundle symbolic name and version |
| 789 | // attributes, add them since the spec says they are there implicitly. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 790 | clause.m_attrs.put(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, bsn); |
| 791 | clause.m_attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, bv); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 792 | } |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 793 | else if (!mv.equals("2")) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 794 | { |
| 795 | // R3 bundles cannot have directives on their exports. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 796 | if (!clause.m_dirs.isEmpty()) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 797 | { |
| 798 | throw new BundleException("R3 exports cannot contain directives."); |
| 799 | } |
| 800 | |
| 801 | // Remove and ignore all attributes other than version. |
| 802 | // NOTE: This is checking for "version" rather than "specification-version" |
| 803 | // because the package class normalizes to "version" to avoid having |
| 804 | // future special cases. This could be changed if more strict behavior |
| 805 | // is required. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 806 | if (!clause.m_attrs.isEmpty()) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 807 | { |
| 808 | // R3 package capabilities should only have a version attribute. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 809 | Object pkgVersion = clause.m_attrs.get(BundleCapabilityImpl.VERSION_ATTR); |
| 810 | pkgVersion = (pkgVersion == null) |
| 811 | ? Version.emptyVersion |
| 812 | : pkgVersion; |
| 813 | for (Entry<String, Object> entry : clause.m_attrs.entrySet()) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 814 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 815 | if (!entry.getKey().equals(BundleCapabilityImpl.VERSION_ATTR)) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 816 | { |
| 817 | logger.log( |
| 818 | Logger.LOG_WARNING, |
| 819 | "Unknown R3 export attribute: " |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 820 | + entry.getKey()); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 821 | } |
| 822 | } |
| 823 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 824 | // Remove all other attributes except package version. |
| 825 | clause.m_attrs.clear(); |
| 826 | clause.m_attrs.put(BundleCapabilityImpl.VERSION_ATTR, pkgVersion); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 827 | } |
| 828 | } |
| 829 | } |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 830 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 831 | return clauses; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 832 | } |
| 833 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 834 | private static List<BundleCapability> convertExports( |
| 835 | List<ParsedHeaderClause> clauses, BundleRevision owner) |
| 836 | { |
| 837 | List<BundleCapability> capList = new ArrayList(); |
| 838 | for (ParsedHeaderClause clause : clauses) |
| 839 | { |
| 840 | for (String pkgName : clause.m_paths) |
| 841 | { |
| 842 | // Prepend the package name to the array of attributes. |
| 843 | Map<String, Object> attrs = clause.m_attrs; |
| 844 | Map<String, Object> newAttrs = new HashMap<String, Object>(attrs.size() + 1); |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 845 | newAttrs.putAll(attrs); |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 846 | newAttrs.put( |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 847 | BundleRevision.PACKAGE_NAMESPACE, |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 848 | pkgName); |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 849 | |
| 850 | // Create package capability and add to capability list. |
| 851 | capList.add( |
| 852 | new BundleCapabilityImpl( |
| 853 | owner, |
Richard S. Hall | 2c0bf6b | 2011-06-07 18:00:08 +0000 | [diff] [blame] | 854 | BundleRevision.PACKAGE_NAMESPACE, |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 855 | clause.m_dirs, |
| 856 | newAttrs)); |
| 857 | } |
| 858 | } |
| 859 | |
| 860 | return capList; |
| 861 | } |
| 862 | |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 863 | public String getManifestVersion() |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 864 | { |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 865 | String manifestVersion = getManifestVersion(m_headerMap); |
| 866 | return (manifestVersion == null) ? "1" : manifestVersion; |
| 867 | } |
| 868 | |
| 869 | private static String getManifestVersion(Map headerMap) |
| 870 | { |
| 871 | String manifestVersion = (String) headerMap.get(Constants.BUNDLE_MANIFESTVERSION); |
| 872 | return (manifestVersion == null) ? null : manifestVersion.trim(); |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 873 | } |
| 874 | |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 875 | public int getActivationPolicy() |
| 876 | { |
| 877 | return m_activationPolicy; |
| 878 | } |
| 879 | |
Richard S. Hall | 10d9d2c | 2009-06-12 20:21:59 +0000 | [diff] [blame] | 880 | public String getActivationIncludeDirective() |
| 881 | { |
| 882 | return m_activationIncludeDir; |
| 883 | } |
| 884 | |
| 885 | public String getActivationExcludeDirective() |
| 886 | { |
| 887 | return m_activationExcludeDir; |
| 888 | } |
| 889 | |
Karl Pauls | 7129443 | 2009-03-16 23:34:01 +0000 | [diff] [blame] | 890 | public boolean isExtension() |
| 891 | { |
| 892 | return m_isExtension; |
| 893 | } |
| 894 | |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 895 | public String getSymbolicName() |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 896 | { |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 897 | return m_bundleSymbolicName; |
| 898 | } |
| 899 | |
| 900 | public Version getBundleVersion() |
| 901 | { |
| 902 | return m_bundleVersion; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 903 | } |
| 904 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 905 | public List<BundleCapability> getCapabilities() |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 906 | { |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 907 | return m_capabilities; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 908 | } |
| 909 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 910 | public List<BundleRequirement> getRequirements() |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 911 | { |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 912 | return m_requirements; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 913 | } |
| 914 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 915 | public List<R4LibraryClause> getLibraryClauses() |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 916 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 917 | return m_libraryClauses; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 918 | } |
| 919 | |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 920 | /** |
| 921 | * <p> |
| 922 | * This method returns the selected native library metadata from |
| 923 | * the manifest. The information is not the raw metadata from the |
Richard S. Hall | 6bae339 | 2009-07-15 15:43:44 +0000 | [diff] [blame] | 924 | * manifest, but is the native library clause selected according |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 925 | * to the OSGi native library clause selection policy. The metadata |
| 926 | * returned by this method will be attached directly to a module and |
| 927 | * used for finding its native libraries at run time. To inspect the |
| 928 | * raw native library metadata refer to <tt>getLibraryClauses()</tt>. |
| 929 | * </p> |
Richard S. Hall | 6bae339 | 2009-07-15 15:43:44 +0000 | [diff] [blame] | 930 | * <p> |
| 931 | * This method returns one of three values: |
| 932 | * </p> |
| 933 | * <ul> |
| 934 | * <li><tt>null</tt> - if the are no native libraries for this module; |
| 935 | * this may also indicate the native libraries are optional and |
| 936 | * did not match the current platform.</li> |
| 937 | * <li>Zero-length <tt>R4Library</tt> array - if no matching native library |
| 938 | * clause was found; this bundle should not resolve.</li> |
| 939 | * <li>Nonzero-length <tt>R4Library</tt> array - the native libraries |
| 940 | * associated with the matching native library clause.</li> |
| 941 | * </ul> |
| 942 | * |
| 943 | * @return <tt>null</tt> if there are no native libraries, a zero-length |
| 944 | * array if no libraries matched, or an array of selected libraries. |
Richard S. Hall | 5eda19c | 2008-02-29 19:52:53 +0000 | [diff] [blame] | 945 | **/ |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 946 | public List<R4Library> getLibraries() |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 947 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 948 | ArrayList<R4Library> libs = null; |
Richard S. Hall | 6bae339 | 2009-07-15 15:43:44 +0000 | [diff] [blame] | 949 | try |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 950 | { |
Richard S. Hall | 6bae339 | 2009-07-15 15:43:44 +0000 | [diff] [blame] | 951 | R4LibraryClause clause = getSelectedLibraryClause(); |
| 952 | if (clause != null) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 953 | { |
Richard S. Hall | 6bae339 | 2009-07-15 15:43:44 +0000 | [diff] [blame] | 954 | String[] entries = clause.getLibraryEntries(); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 955 | libs = new ArrayList<R4Library>(entries.length); |
Richard S. Hall | 6bae339 | 2009-07-15 15:43:44 +0000 | [diff] [blame] | 956 | int current = 0; |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 957 | for (int i = 0; i < entries.length; i++) |
Karl Pauls | fb846a4 | 2007-12-18 22:39:00 +0000 | [diff] [blame] | 958 | { |
Richard S. Hall | 5eda19c | 2008-02-29 19:52:53 +0000 | [diff] [blame] | 959 | String name = getName(entries[i]); |
Karl Pauls | fb846a4 | 2007-12-18 22:39:00 +0000 | [diff] [blame] | 960 | boolean found = false; |
| 961 | for (int j = 0; !found && (j < current); j++) |
| 962 | { |
Richard S. Hall | 5eda19c | 2008-02-29 19:52:53 +0000 | [diff] [blame] | 963 | found = getName(entries[j]).equals(name); |
Karl Pauls | fb846a4 | 2007-12-18 22:39:00 +0000 | [diff] [blame] | 964 | } |
| 965 | if (!found) |
| 966 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 967 | libs.add(new R4Library( |
Richard S. Hall | 5eda19c | 2008-02-29 19:52:53 +0000 | [diff] [blame] | 968 | clause.getLibraryEntries()[i], |
Karl Pauls | fb846a4 | 2007-12-18 22:39:00 +0000 | [diff] [blame] | 969 | clause.getOSNames(), clause.getProcessors(), clause.getOSVersions(), |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 970 | clause.getLanguages(), clause.getSelectionFilter())); |
Carsten Ziegeler | fc8029a | 2008-05-14 16:26:03 +0000 | [diff] [blame] | 971 | } |
Karl Pauls | fb846a4 | 2007-12-18 22:39:00 +0000 | [diff] [blame] | 972 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 973 | libs.trimToSize(); |
Karl Pauls | fb846a4 | 2007-12-18 22:39:00 +0000 | [diff] [blame] | 974 | } |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 975 | } |
Richard S. Hall | 6bae339 | 2009-07-15 15:43:44 +0000 | [diff] [blame] | 976 | catch (Exception ex) |
| 977 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 978 | libs = new ArrayList<R4Library>(0); |
Richard S. Hall | 6bae339 | 2009-07-15 15:43:44 +0000 | [diff] [blame] | 979 | } |
| 980 | return libs; |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 981 | } |
| 982 | |
Karl Pauls | fb846a4 | 2007-12-18 22:39:00 +0000 | [diff] [blame] | 983 | private String getName(String path) |
| 984 | { |
| 985 | int idx = path.lastIndexOf('/'); |
| 986 | if (idx > -1) |
| 987 | { |
| 988 | return path.substring(idx); |
| 989 | } |
| 990 | return path; |
| 991 | } |
| 992 | |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 993 | private R4LibraryClause getSelectedLibraryClause() throws BundleException |
| 994 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 995 | if ((m_libraryClauses != null) && (m_libraryClauses.size() > 0)) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 996 | { |
| 997 | List clauseList = new ArrayList(); |
| 998 | |
| 999 | // Search for matching native clauses. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1000 | for (R4LibraryClause libraryClause : m_libraryClauses) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1001 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1002 | if (libraryClause.match(m_configMap)) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1003 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1004 | clauseList.add(libraryClause); |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1005 | } |
| 1006 | } |
| 1007 | |
| 1008 | // Select the matching native clause. |
| 1009 | int selected = 0; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1010 | if (clauseList.isEmpty()) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1011 | { |
| 1012 | // If optional clause exists, no error thrown. |
| 1013 | if (m_libraryHeadersOptional) |
| 1014 | { |
| 1015 | return null; |
| 1016 | } |
| 1017 | else |
| 1018 | { |
| 1019 | throw new BundleException("Unable to select a native library clause."); |
| 1020 | } |
| 1021 | } |
| 1022 | else if (clauseList.size() == 1) |
| 1023 | { |
| 1024 | selected = 0; |
| 1025 | } |
| 1026 | else if (clauseList.size() > 1) |
| 1027 | { |
| 1028 | selected = firstSortedClause(clauseList); |
| 1029 | } |
| 1030 | return ((R4LibraryClause) clauseList.get(selected)); |
| 1031 | } |
| 1032 | |
| 1033 | return null; |
| 1034 | } |
| 1035 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1036 | private int firstSortedClause(List<R4LibraryClause> clauseList) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1037 | { |
| 1038 | ArrayList indexList = new ArrayList(); |
| 1039 | ArrayList selection = new ArrayList(); |
| 1040 | |
| 1041 | // Init index list |
| 1042 | for (int i = 0; i < clauseList.size(); i++) |
| 1043 | { |
| 1044 | indexList.add("" + i); |
| 1045 | } |
| 1046 | |
| 1047 | // Select clause with 'osversion' range declared |
| 1048 | // and get back the max floor of 'osversion' ranges. |
| 1049 | Version osVersionRangeMaxFloor = new Version(0, 0, 0); |
| 1050 | for (int i = 0; i < indexList.size(); i++) |
| 1051 | { |
| 1052 | int index = Integer.parseInt(indexList.get(i).toString()); |
| 1053 | String[] osversions = ((R4LibraryClause) clauseList.get(index)).getOSVersions(); |
| 1054 | if (osversions != null) |
| 1055 | { |
| 1056 | selection.add("" + indexList.get(i)); |
| 1057 | } |
| 1058 | for (int k = 0; (osversions != null) && (k < osversions.length); k++) |
| 1059 | { |
| 1060 | VersionRange range = VersionRange.parse(osversions[k]); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1061 | if ((range.getFloor()).compareTo(osVersionRangeMaxFloor) >= 0) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1062 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1063 | osVersionRangeMaxFloor = range.getFloor(); |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1064 | } |
| 1065 | } |
| 1066 | } |
| 1067 | |
| 1068 | if (selection.size() == 1) |
| 1069 | { |
| 1070 | return Integer.parseInt(selection.get(0).toString()); |
| 1071 | } |
| 1072 | else if (selection.size() > 1) |
| 1073 | { |
| 1074 | // Keep only selected clauses with an 'osversion' |
| 1075 | // equal to the max floor of 'osversion' ranges. |
| 1076 | indexList = selection; |
| 1077 | selection = new ArrayList(); |
| 1078 | for (int i = 0; i < indexList.size(); i++) |
| 1079 | { |
| 1080 | int index = Integer.parseInt(indexList.get(i).toString()); |
| 1081 | String[] osversions = ((R4LibraryClause) clauseList.get(index)).getOSVersions(); |
| 1082 | for (int k = 0; k < osversions.length; k++) |
| 1083 | { |
| 1084 | VersionRange range = VersionRange.parse(osversions[k]); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1085 | if ((range.getFloor()).compareTo(osVersionRangeMaxFloor) >= 0) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1086 | { |
| 1087 | selection.add("" + indexList.get(i)); |
| 1088 | } |
| 1089 | } |
| 1090 | } |
| 1091 | } |
| 1092 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1093 | if (selection.isEmpty()) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1094 | { |
| 1095 | // Re-init index list. |
| 1096 | selection.clear(); |
| 1097 | indexList.clear(); |
| 1098 | for (int i = 0; i < clauseList.size(); i++) |
| 1099 | { |
| 1100 | indexList.add("" + i); |
| 1101 | } |
| 1102 | } |
| 1103 | else if (selection.size() == 1) |
| 1104 | { |
| 1105 | return Integer.parseInt(selection.get(0).toString()); |
| 1106 | } |
| 1107 | else |
| 1108 | { |
| 1109 | indexList = selection; |
| 1110 | selection.clear(); |
| 1111 | } |
| 1112 | |
| 1113 | // Keep only clauses with 'language' declared. |
| 1114 | for (int i = 0; i < indexList.size(); i++) |
| 1115 | { |
| 1116 | int index = Integer.parseInt(indexList.get(i).toString()); |
| 1117 | if (((R4LibraryClause) clauseList.get(index)).getLanguages() != null) |
| 1118 | { |
| 1119 | selection.add("" + indexList.get(i)); |
| 1120 | } |
| 1121 | } |
| 1122 | |
| 1123 | // Return the first sorted clause |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1124 | if (selection.isEmpty()) |
Richard S. Hall | 8d116d4 | 2006-09-01 19:23:28 +0000 | [diff] [blame] | 1125 | { |
| 1126 | return 0; |
| 1127 | } |
| 1128 | else |
| 1129 | { |
| 1130 | return Integer.parseInt(selection.get(0).toString()); |
| 1131 | } |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1132 | } |
| 1133 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1134 | private static List<ParsedHeaderClause> calculateImplicitImports( |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1135 | List<BundleCapability> exports, List<ParsedHeaderClause> imports) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1136 | throws BundleException |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1137 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1138 | List<ParsedHeaderClause> clauseList = new ArrayList(); |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1139 | |
| 1140 | // Since all R3 exports imply an import, add a corresponding |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 1141 | // requirement for each existing export capability. Do not |
| 1142 | // duplicate imports. |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1143 | Map map = new HashMap(); |
| 1144 | // Add existing imports. |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1145 | for (int impIdx = 0; impIdx < imports.size(); impIdx++) |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1146 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1147 | for (int pathIdx = 0; pathIdx < imports.get(impIdx).m_paths.size(); pathIdx++) |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 1148 | { |
| 1149 | map.put( |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1150 | imports.get(impIdx).m_paths.get(pathIdx), |
| 1151 | imports.get(impIdx).m_paths.get(pathIdx)); |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 1152 | } |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1153 | } |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 1154 | // Add import requirement for each export capability. |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1155 | for (int i = 0; i < exports.size(); i++) |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1156 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1157 | if (map.get(exports.get(i).getAttributes() |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 1158 | .get(BundleRevision.PACKAGE_NAMESPACE)) == null) |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1159 | { |
Richard S. Hall | a5158a2 | 2006-12-13 21:20:48 +0000 | [diff] [blame] | 1160 | // Convert Version to VersionRange. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1161 | Map<String, Object> attrs = new HashMap<String, Object>(); |
| 1162 | Object version = exports.get(i).getAttributes().get(Constants.VERSION_ATTRIBUTE); |
| 1163 | if (version != null) |
Richard S. Hall | a5158a2 | 2006-12-13 21:20:48 +0000 | [diff] [blame] | 1164 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1165 | attrs.put( |
| 1166 | Constants.VERSION_ATTRIBUTE, |
| 1167 | VersionRange.parse(version.toString())); |
Richard S. Hall | a5158a2 | 2006-12-13 21:20:48 +0000 | [diff] [blame] | 1168 | } |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 1169 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1170 | List<String> paths = new ArrayList(); |
| 1171 | paths.add((String) |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 1172 | exports.get(i).getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1173 | clauseList.add( |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1174 | new ParsedHeaderClause( |
| 1175 | paths, Collections.EMPTY_MAP, attrs, Collections.EMPTY_MAP)); |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1176 | } |
| 1177 | } |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1178 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1179 | return clauseList; |
| 1180 | } |
| 1181 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1182 | private static List<BundleCapability> calculateImplicitUses( |
| 1183 | List<BundleCapability> exports, List<ParsedHeaderClause> imports) |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1184 | throws BundleException |
| 1185 | { |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1186 | // Add a "uses" directive onto each export of R3 bundles |
| 1187 | // that references every other import (which will include |
| 1188 | // exports, since export implies import); this is |
| 1189 | // necessary since R3 bundles assumed a single class space, |
| 1190 | // but R4 allows for multiple class spaces. |
| 1191 | String usesValue = ""; |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1192 | for (int i = 0; i < imports.size(); i++) |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1193 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1194 | for (int pathIdx = 0; pathIdx < imports.get(i).m_paths.size(); pathIdx++) |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 1195 | { |
| 1196 | usesValue = usesValue |
| 1197 | + ((usesValue.length() > 0) ? "," : "") |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1198 | + imports.get(i).m_paths.get(pathIdx); |
Richard S. Hall | 862eca1 | 2007-01-22 07:09:25 +0000 | [diff] [blame] | 1199 | } |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1200 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1201 | for (int i = 0; i < exports.size(); i++) |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1202 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1203 | Map<String, String> dirs = new HashMap<String, String>(1); |
| 1204 | dirs.put(Constants.USES_DIRECTIVE, usesValue); |
| 1205 | exports.set(i, new BundleCapabilityImpl( |
| 1206 | exports.get(i).getRevision(), |
Richard S. Hall | 2c0bf6b | 2011-06-07 18:00:08 +0000 | [diff] [blame] | 1207 | BundleRevision.PACKAGE_NAMESPACE, |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1208 | dirs, |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1209 | exports.get(i).getAttributes())); |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1210 | } |
| 1211 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1212 | return exports; |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1213 | } |
| 1214 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1215 | private static boolean checkExtensionBundle(Map headerMap) throws BundleException |
Richard S. Hall | a2878c1 | 2006-07-21 14:50:07 +0000 | [diff] [blame] | 1216 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1217 | Object extension = parseExtensionBundleHeader( |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1218 | (String) headerMap.get(Constants.FRAGMENT_HOST)); |
Karl Pauls | 7129443 | 2009-03-16 23:34:01 +0000 | [diff] [blame] | 1219 | |
Karl Pauls | a2ecacc | 2008-10-21 21:56:31 +0000 | [diff] [blame] | 1220 | if (extension != null) |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1221 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1222 | if (!(Constants.EXTENSION_FRAMEWORK.equals(extension) || |
| 1223 | Constants.EXTENSION_BOOTCLASSPATH.equals(extension))) |
Karl Pauls | a2ecacc | 2008-10-21 21:56:31 +0000 | [diff] [blame] | 1224 | { |
| 1225 | throw new BundleException( |
| 1226 | "Extension bundle must have either 'extension:=framework' or 'extension:=bootclasspath'"); |
| 1227 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1228 | if (headerMap.containsKey(Constants.IMPORT_PACKAGE) || |
| 1229 | headerMap.containsKey(Constants.REQUIRE_BUNDLE) || |
| 1230 | headerMap.containsKey(Constants.BUNDLE_NATIVECODE) || |
| 1231 | headerMap.containsKey(Constants.DYNAMICIMPORT_PACKAGE) || |
| 1232 | headerMap.containsKey(Constants.BUNDLE_ACTIVATOR)) |
Richard S. Hall | 436c0fb | 2009-05-13 20:34:42 +0000 | [diff] [blame] | 1233 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1234 | throw new BundleException("Invalid extension bundle manifest"); |
Richard S. Hall | 436c0fb | 2009-05-13 20:34:42 +0000 | [diff] [blame] | 1235 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1236 | return true; |
Richard S. Hall | 436c0fb | 2009-05-13 20:34:42 +0000 | [diff] [blame] | 1237 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1238 | return false; |
Richard S. Hall | 436c0fb | 2009-05-13 20:34:42 +0000 | [diff] [blame] | 1239 | } |
| 1240 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1241 | private static BundleCapabilityImpl parseBundleSymbolicName( |
| 1242 | BundleRevision owner, Map headerMap) |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 1243 | throws BundleException |
| 1244 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1245 | List<ParsedHeaderClause> clauses = parseStandardHeader( |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 1246 | (String) headerMap.get(Constants.BUNDLE_SYMBOLICNAME)); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1247 | if (clauses.size() > 0) |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 1248 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1249 | if (clauses.size() > 1) |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 1250 | { |
| 1251 | throw new BundleException( |
| 1252 | "Cannot have multiple symbolic names: " |
| 1253 | + headerMap.get(Constants.BUNDLE_SYMBOLICNAME)); |
| 1254 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1255 | else if (clauses.get(0).m_paths.size() > 1) |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 1256 | { |
| 1257 | throw new BundleException( |
| 1258 | "Cannot have multiple symbolic names: " |
| 1259 | + headerMap.get(Constants.BUNDLE_SYMBOLICNAME)); |
| 1260 | } |
| 1261 | |
| 1262 | // Get bundle version. |
Richard S. Hall | 7561a37 | 2009-01-27 19:34:12 +0000 | [diff] [blame] | 1263 | Version bundleVersion = Version.emptyVersion; |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 1264 | if (headerMap.get(Constants.BUNDLE_VERSION) != null) |
| 1265 | { |
| 1266 | try |
| 1267 | { |
Richard S. Hall | 7d5669c | 2009-10-20 20:31:12 +0000 | [diff] [blame] | 1268 | bundleVersion = Version.parseVersion( |
| 1269 | (String) headerMap.get(Constants.BUNDLE_VERSION)); |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 1270 | } |
| 1271 | catch (RuntimeException ex) |
| 1272 | { |
| 1273 | // R4 bundle versions must parse, R3 bundle version may not. |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1274 | String mv = getManifestVersion(headerMap); |
| 1275 | if (mv != null) |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 1276 | { |
| 1277 | throw ex; |
| 1278 | } |
| 1279 | bundleVersion = Version.emptyVersion; |
| 1280 | } |
| 1281 | } |
| 1282 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1283 | // Create a require capability and return it. |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1284 | String symName = (String) clauses.get(0).m_paths.get(0); |
Richard S. Hall | aa7f100 | 2011-07-06 14:58:47 +0000 | [diff] [blame] | 1285 | clauses.get(0).m_attrs.put(BundleRevision.BUNDLE_NAMESPACE, symName); |
| 1286 | clauses.get(0).m_attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, bundleVersion); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1287 | return new BundleCapabilityImpl( |
Richard S. Hall | 7d5669c | 2009-10-20 20:31:12 +0000 | [diff] [blame] | 1288 | owner, |
Richard S. Hall | 2c0bf6b | 2011-06-07 18:00:08 +0000 | [diff] [blame] | 1289 | BundleRevision.BUNDLE_NAMESPACE, |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1290 | clauses.get(0).m_dirs, |
Richard S. Hall | aa7f100 | 2011-07-06 14:58:47 +0000 | [diff] [blame] | 1291 | clauses.get(0).m_attrs); |
Richard S. Hall | 9802e3f | 2008-07-07 01:37:22 +0000 | [diff] [blame] | 1292 | } |
| 1293 | |
| 1294 | return null; |
| 1295 | } |
| 1296 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1297 | private static List<BundleRequirementImpl> parseFragmentHost( |
| 1298 | Logger logger, BundleRevision owner, Map headerMap) |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1299 | throws BundleException |
| 1300 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1301 | List<BundleRequirementImpl> reqs = new ArrayList(); |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1302 | |
| 1303 | String mv = getManifestVersion(headerMap); |
| 1304 | if ((mv != null) && mv.equals("2")) |
| 1305 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1306 | List<ParsedHeaderClause> clauses = parseStandardHeader( |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1307 | (String) headerMap.get(Constants.FRAGMENT_HOST)); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1308 | if (clauses.size() > 0) |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1309 | { |
| 1310 | // Make sure that only one fragment host symbolic name is specified. |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1311 | if (clauses.size() > 1) |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1312 | { |
| 1313 | throw new BundleException( |
| 1314 | "Fragments cannot have multiple hosts: " |
| 1315 | + headerMap.get(Constants.FRAGMENT_HOST)); |
| 1316 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1317 | else if (clauses.get(0).m_paths.size() > 1) |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1318 | { |
| 1319 | throw new BundleException( |
| 1320 | "Fragments cannot have multiple hosts: " |
| 1321 | + headerMap.get(Constants.FRAGMENT_HOST)); |
| 1322 | } |
| 1323 | |
Richard S. Hall | 1172e83 | 2010-07-09 14:14:15 +0000 | [diff] [blame] | 1324 | // Strip all attributes other than bundle-version. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1325 | for (Iterator<Entry<String, Object>> it = |
| 1326 | clauses.get(0).m_attrs.entrySet().iterator(); |
| 1327 | it.hasNext(); ) |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1328 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1329 | Entry<String, Object> entry = it.next(); |
| 1330 | if (!entry.getKey().equals(Constants.BUNDLE_VERSION_ATTRIBUTE)) |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1331 | { |
Richard S. Hall | 1172e83 | 2010-07-09 14:14:15 +0000 | [diff] [blame] | 1332 | it.remove(); |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1333 | } |
| 1334 | } |
| 1335 | |
Richard S. Hall | 1172e83 | 2010-07-09 14:14:15 +0000 | [diff] [blame] | 1336 | // If the bundle-version attribute is specified, then convert |
| 1337 | // it to the proper type. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1338 | Object value = clauses.get(0).m_attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE); |
| 1339 | if (value != null) |
Richard S. Hall | 1172e83 | 2010-07-09 14:14:15 +0000 | [diff] [blame] | 1340 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1341 | clauses.get(0).m_attrs.put( |
| 1342 | Constants.BUNDLE_VERSION_ATTRIBUTE, |
| 1343 | VersionRange.parse(value.toString())); |
Richard S. Hall | 1172e83 | 2010-07-09 14:14:15 +0000 | [diff] [blame] | 1344 | } |
| 1345 | |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1346 | // Prepend the host symbolic name to the array of attributes. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1347 | Map<String, Object> attrs = clauses.get(0).m_attrs; |
| 1348 | Map<String, Object> newAttrs = new HashMap<String, Object>(attrs.size() + 1); |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 1349 | newAttrs.putAll(attrs); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1350 | newAttrs.put( |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 1351 | BundleRevision.HOST_NAMESPACE, |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1352 | clauses.get(0).m_paths.get(0)); |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 1353 | |
| 1354 | // Create filter now so we can inject filter directive. |
| 1355 | SimpleFilter sf = BundleRequirementImpl.convertToFilter(newAttrs); |
| 1356 | |
| 1357 | // Inject filter directive. |
| 1358 | // TODO: OSGi R4.3 - Can we insert this on demand somehow? |
| 1359 | Map<String, String> dirs = clauses.get(0).m_dirs; |
| 1360 | Map<String, String> newDirs = new HashMap<String, String>(dirs.size() + 1); |
| 1361 | newDirs.putAll(dirs); |
| 1362 | newDirs.put( |
| 1363 | Constants.FILTER_DIRECTIVE, |
| 1364 | sf.toString()); |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1365 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1366 | reqs.add(new BundleRequirementImpl( |
Richard S. Hall | 2c0bf6b | 2011-06-07 18:00:08 +0000 | [diff] [blame] | 1367 | owner, BundleRevision.HOST_NAMESPACE, |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 1368 | newDirs, |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1369 | newAttrs)); |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1370 | } |
| 1371 | } |
Richard S. Hall | c3a17b7 | 2010-03-04 17:19:49 +0000 | [diff] [blame] | 1372 | else if (headerMap.get(Constants.FRAGMENT_HOST) != null) |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1373 | { |
Richard S. Hall | c4cca30 | 2010-03-04 17:12:48 +0000 | [diff] [blame] | 1374 | String s = (String) headerMap.get(Constants.BUNDLE_SYMBOLICNAME); |
| 1375 | s = (s == null) ? (String) headerMap.get(Constants.BUNDLE_NAME) : s; |
| 1376 | s = (s == null) ? headerMap.toString() : s; |
Richard S. Hall | 4a546d0 | 2010-09-15 20:52:08 +0000 | [diff] [blame] | 1377 | logger.log( |
| 1378 | owner.getBundle(), |
| 1379 | Logger.LOG_WARNING, |
| 1380 | "Only R4 bundles can be fragments: " + s); |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1381 | } |
| 1382 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1383 | return reqs; |
Richard S. Hall | 1563de2 | 2009-10-22 16:46:48 +0000 | [diff] [blame] | 1384 | } |
| 1385 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1386 | public static List<BundleCapability> parseExportHeader( |
| 1387 | Logger logger, BundleRevision owner, String header, String bsn, Version bv) |
Richard S. Hall | 436c0fb | 2009-05-13 20:34:42 +0000 | [diff] [blame] | 1388 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1389 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1390 | List<BundleCapability> caps = null; |
Richard S. Hall | 436c0fb | 2009-05-13 20:34:42 +0000 | [diff] [blame] | 1391 | try |
| 1392 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1393 | List<ParsedHeaderClause> exportClauses = parseStandardHeader(header); |
| 1394 | exportClauses = normalizeExportClauses(logger, exportClauses, "2", bsn, bv); |
| 1395 | caps = convertExports(exportClauses, owner); |
Richard S. Hall | 436c0fb | 2009-05-13 20:34:42 +0000 | [diff] [blame] | 1396 | } |
| 1397 | catch (BundleException ex) |
| 1398 | { |
| 1399 | caps = null; |
| 1400 | } |
| 1401 | return caps; |
| 1402 | } |
| 1403 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1404 | private static List<ParsedHeaderClause> normalizeRequireClauses( |
| 1405 | Logger logger, List<ParsedHeaderClause> clauses, String mv) |
Richard S. Hall | 4151e90 | 2006-12-27 16:11:16 +0000 | [diff] [blame] | 1406 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1407 | // R3 bundles cannot require other bundles. |
| 1408 | if (!mv.equals("2")) |
Richard S. Hall | 4151e90 | 2006-12-27 16:11:16 +0000 | [diff] [blame] | 1409 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1410 | clauses.clear(); |
Richard S. Hall | 4151e90 | 2006-12-27 16:11:16 +0000 | [diff] [blame] | 1411 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1412 | else |
Richard S. Hall | 4151e90 | 2006-12-27 16:11:16 +0000 | [diff] [blame] | 1413 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1414 | // Convert bundle version attribute to VersionRange type. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1415 | for (ParsedHeaderClause clause : clauses) |
Richard S. Hall | 4151e90 | 2006-12-27 16:11:16 +0000 | [diff] [blame] | 1416 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1417 | Object value = clause.m_attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1418 | if (value != null) |
Richard S. Hall | fa78057 | 2009-01-23 16:01:53 +0000 | [diff] [blame] | 1419 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1420 | clause.m_attrs.put( |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1421 | Constants.BUNDLE_VERSION_ATTRIBUTE, |
| 1422 | VersionRange.parse(value.toString())); |
Richard S. Hall | fa78057 | 2009-01-23 16:01:53 +0000 | [diff] [blame] | 1423 | } |
Richard S. Hall | 4151e90 | 2006-12-27 16:11:16 +0000 | [diff] [blame] | 1424 | } |
| 1425 | } |
| 1426 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1427 | return clauses; |
Richard S. Hall | 4151e90 | 2006-12-27 16:11:16 +0000 | [diff] [blame] | 1428 | } |
| 1429 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1430 | private static List<BundleRequirementImpl> convertRequires( |
| 1431 | List<ParsedHeaderClause> clauses, BundleRevision owner) |
Richard S. Hall | 860ee30 | 2006-12-27 18:32:04 +0000 | [diff] [blame] | 1432 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1433 | List<BundleRequirementImpl> reqList = new ArrayList(); |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1434 | for (ParsedHeaderClause clause : clauses) |
Richard S. Hall | 860ee30 | 2006-12-27 18:32:04 +0000 | [diff] [blame] | 1435 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1436 | for (String path : clause.m_paths) |
Richard S. Hall | 860ee30 | 2006-12-27 18:32:04 +0000 | [diff] [blame] | 1437 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1438 | // Prepend the bundle symbolic name to the array of attributes. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1439 | Map<String, Object> attrs = clause.m_attrs; |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1440 | // Note that we use a linked hash map here to ensure the |
| 1441 | // package attribute is first, which will make indexing |
| 1442 | // more efficient. |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 1443 | // TODO: OSGi R4.3 - This ordering fix is a hack...perhaps we should use the standard "key" |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1444 | // notion where namespace is also the name of the key attribute. |
Richard S. Hall | 860ee30 | 2006-12-27 18:32:04 +0000 | [diff] [blame] | 1445 | // Prepend the symbolic name to the array of attributes. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1446 | Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1); |
| 1447 | newAttrs.put( |
Richard S. Hall | c4e7599 | 2011-06-15 18:57:20 +0000 | [diff] [blame] | 1448 | BundleRevision.BUNDLE_NAMESPACE, |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1449 | path); |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1450 | newAttrs.putAll(attrs); |
Richard S. Hall | 860ee30 | 2006-12-27 18:32:04 +0000 | [diff] [blame] | 1451 | |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 1452 | // Create filter now so we can inject filter directive. |
| 1453 | SimpleFilter sf = BundleRequirementImpl.convertToFilter(newAttrs); |
| 1454 | |
| 1455 | // Inject filter directive. |
| 1456 | // TODO: OSGi R4.3 - Can we insert this on demand somehow? |
| 1457 | Map<String, String> dirs = clause.m_dirs; |
| 1458 | Map<String, String> newDirs = new HashMap<String, String>(dirs.size() + 1); |
| 1459 | newDirs.putAll(dirs); |
| 1460 | newDirs.put( |
| 1461 | Constants.FILTER_DIRECTIVE, |
| 1462 | sf.toString()); |
| 1463 | |
Richard S. Hall | 860ee30 | 2006-12-27 18:32:04 +0000 | [diff] [blame] | 1464 | // Create package requirement and add to requirement list. |
| 1465 | reqList.add( |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1466 | new BundleRequirementImpl( |
Richard S. Hall | 1a879e5 | 2010-04-18 19:22:48 +0000 | [diff] [blame] | 1467 | owner, |
Richard S. Hall | 2c0bf6b | 2011-06-07 18:00:08 +0000 | [diff] [blame] | 1468 | BundleRevision.BUNDLE_NAMESPACE, |
Richard S. Hall | 9b94041 | 2011-07-20 18:19:02 +0000 | [diff] [blame^] | 1469 | newDirs, |
Richard S. Hall | 860ee30 | 2006-12-27 18:32:04 +0000 | [diff] [blame] | 1470 | newAttrs)); |
| 1471 | } |
| 1472 | } |
| 1473 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1474 | return reqList; |
Richard S. Hall | 860ee30 | 2006-12-27 18:32:04 +0000 | [diff] [blame] | 1475 | } |
| 1476 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1477 | public static String parseExtensionBundleHeader(String header) |
Richard S. Hall | 2e0c022 | 2009-05-01 19:11:02 +0000 | [diff] [blame] | 1478 | throws BundleException |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1479 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1480 | List<ParsedHeaderClause> clauses = parseStandardHeader(header); |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1481 | |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1482 | String result = null; |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1483 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1484 | if (clauses.size() == 1) |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1485 | { |
Richard S. Hall | 2e0c022 | 2009-05-01 19:11:02 +0000 | [diff] [blame] | 1486 | // See if there is the "extension" directive. |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1487 | for (Entry<String, String> entry : clauses.get(0).m_dirs.entrySet()) |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1488 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1489 | if (Constants.EXTENSION_DIRECTIVE.equals(entry.getKey())) |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1490 | { |
Richard S. Hall | 2e0c022 | 2009-05-01 19:11:02 +0000 | [diff] [blame] | 1491 | // If the extension directive is specified, make sure |
| 1492 | // the target is the system bundle. |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1493 | if (FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(clauses.get(0).m_paths.get(0)) || |
| 1494 | Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(clauses.get(0).m_paths.get(0))) |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1495 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1496 | return entry.getValue(); |
Richard S. Hall | 2e0c022 | 2009-05-01 19:11:02 +0000 | [diff] [blame] | 1497 | } |
| 1498 | else |
| 1499 | { |
| 1500 | throw new BundleException( |
| 1501 | "Only the system bundle can have extension bundles."); |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1502 | } |
| 1503 | } |
| 1504 | } |
| 1505 | } |
| 1506 | |
| 1507 | return result; |
| 1508 | } |
| 1509 | |
Richard S. Hall | 10d9d2c | 2009-06-12 20:21:59 +0000 | [diff] [blame] | 1510 | private void parseActivationPolicy(Map headerMap) |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 1511 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1512 | m_activationPolicy = BundleRevisionImpl.EAGER_ACTIVATION; |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 1513 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1514 | List<ParsedHeaderClause> clauses = parseStandardHeader( |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 1515 | (String) headerMap.get(Constants.BUNDLE_ACTIVATIONPOLICY)); |
| 1516 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1517 | if (clauses.size() > 0) |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 1518 | { |
| 1519 | // Just look for a "path" matching the lazy policy, ignore |
| 1520 | // everything else. |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1521 | for (String path : clauses.get(0).m_paths) |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 1522 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1523 | if (path.equals(Constants.ACTIVATION_LAZY)) |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 1524 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1525 | m_activationPolicy = BundleRevisionImpl.LAZY_ACTIVATION; |
| 1526 | for (Entry<String, String> entry : clauses.get(0).m_dirs.entrySet()) |
Richard S. Hall | 10d9d2c | 2009-06-12 20:21:59 +0000 | [diff] [blame] | 1527 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1528 | if (entry.getKey().equalsIgnoreCase(Constants.INCLUDE_DIRECTIVE)) |
Richard S. Hall | 10d9d2c | 2009-06-12 20:21:59 +0000 | [diff] [blame] | 1529 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1530 | m_activationIncludeDir = entry.getValue(); |
Richard S. Hall | 10d9d2c | 2009-06-12 20:21:59 +0000 | [diff] [blame] | 1531 | } |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1532 | else if (entry.getKey().equalsIgnoreCase(Constants.EXCLUDE_DIRECTIVE)) |
Richard S. Hall | 10d9d2c | 2009-06-12 20:21:59 +0000 | [diff] [blame] | 1533 | { |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1534 | m_activationExcludeDir = entry.getValue(); |
Richard S. Hall | 10d9d2c | 2009-06-12 20:21:59 +0000 | [diff] [blame] | 1535 | } |
| 1536 | } |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 1537 | break; |
| 1538 | } |
| 1539 | } |
| 1540 | } |
Richard S. Hall | 2a5fb9a | 2009-05-14 15:14:13 +0000 | [diff] [blame] | 1541 | } |
| 1542 | |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1543 | // Like this: path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2, |
| 1544 | // path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2 |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1545 | public static void main(String[] headers) |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1546 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1547 | String header = headers[0]; |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1548 | |
| 1549 | if (header != null) |
| 1550 | { |
| 1551 | if (header.length() == 0) |
| 1552 | { |
| 1553 | throw new IllegalArgumentException( |
| 1554 | "A header cannot be an empty string."); |
| 1555 | } |
| 1556 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1557 | List<ParsedHeaderClause> clauses = parseStandardHeader(header); |
| 1558 | for (ParsedHeaderClause clause : clauses) |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1559 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1560 | System.out.println("PATHS " + clause.m_paths); |
| 1561 | System.out.println(" DIRS " + clause.m_dirs); |
| 1562 | System.out.println(" ATTRS " + clause.m_attrs); |
| 1563 | System.out.println(" TYPES " + clause.m_types); |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1564 | } |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1565 | } |
| 1566 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1567 | // return clauses; |
| 1568 | } |
| 1569 | |
| 1570 | private static List<ParsedHeaderClause> parseStandardHeader(String header) |
| 1571 | { |
| 1572 | List<ParsedHeaderClause> clauses = new ArrayList<ParsedHeaderClause>(); |
| 1573 | if (header != null) |
| 1574 | { |
| 1575 | int[] startIdx = new int[1]; |
| 1576 | startIdx[0] = 0; |
| 1577 | for (int i = 0; i < header.length(); i++) |
| 1578 | { |
| 1579 | clauses.add(parseClause(startIdx, header)); |
| 1580 | i = startIdx[0]; |
| 1581 | } |
| 1582 | } |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1583 | return clauses; |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1584 | } |
| 1585 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1586 | private static ParsedHeaderClause parseClause(int[] startIdx, String header) |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1587 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1588 | ParsedHeaderClause clause = new ParsedHeaderClause( |
| 1589 | new ArrayList<String>(), |
| 1590 | new HashMap<String, String>(), |
| 1591 | new HashMap<String, Object>(), |
| 1592 | new HashMap<String, String>()); |
| 1593 | for (int i = startIdx[0]; i < header.length(); i++) |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1594 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1595 | char c = header.charAt(i); |
| 1596 | if ((c == ':') || (c == '=')) |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1597 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1598 | parseClauseParameters(startIdx, header, clause); |
| 1599 | i = startIdx[0]; |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1600 | break; |
| 1601 | } |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1602 | else if ((c == ';') || (c == ',') || (i == (header.length() - 1))) |
| 1603 | { |
| 1604 | String path; |
| 1605 | if (i == (header.length() - 1)) |
| 1606 | { |
| 1607 | path = header.substring(startIdx[0], header.length()); |
| 1608 | } |
| 1609 | else |
| 1610 | { |
| 1611 | path = header.substring(startIdx[0], i); |
| 1612 | } |
| 1613 | clause.m_paths.add(path.trim()); |
| 1614 | startIdx[0] = i + 1; |
| 1615 | if (c == ',') |
| 1616 | { |
| 1617 | break; |
| 1618 | } |
| 1619 | } |
| 1620 | } |
| 1621 | return clause; |
| 1622 | } |
| 1623 | |
| 1624 | private static void parseClauseParameters( |
| 1625 | int[] startIdx, String header, ParsedHeaderClause clause) |
| 1626 | { |
| 1627 | for (int i = startIdx[0]; i < header.length(); i++) |
| 1628 | { |
| 1629 | char c = header.charAt(i); |
| 1630 | if ((c == ':') && (header.charAt(i + 1) == '=')) |
| 1631 | { |
| 1632 | parseClauseDirective(startIdx, header, clause); |
| 1633 | i = startIdx[0]; |
| 1634 | } |
| 1635 | else if ((c == ':') || (c == '=')) |
| 1636 | { |
| 1637 | parseClauseAttribute(startIdx, header, clause); |
| 1638 | i = startIdx[0]; |
| 1639 | } |
| 1640 | else if (c == ',') |
| 1641 | { |
| 1642 | startIdx[0] = i + 1; |
| 1643 | break; |
| 1644 | } |
| 1645 | } |
| 1646 | } |
| 1647 | |
| 1648 | private static void parseClauseDirective( |
| 1649 | int[] startIdx, String header, ParsedHeaderClause clause) |
| 1650 | { |
| 1651 | String name = null; |
| 1652 | String value = null; |
| 1653 | boolean isQuoted = false; |
| 1654 | boolean isEscaped = false; |
| 1655 | for (int i = startIdx[0]; i < header.length(); i++) |
| 1656 | { |
| 1657 | char c = header.charAt(i); |
| 1658 | if (!isEscaped && (c == '"')) |
| 1659 | { |
| 1660 | isQuoted = !isQuoted; |
| 1661 | } |
| 1662 | |
| 1663 | if (!isEscaped |
| 1664 | && !isQuoted && (c == ':')) |
| 1665 | { |
| 1666 | name = header.substring(startIdx[0], i); |
| 1667 | startIdx[0] = i + 2; |
| 1668 | } |
| 1669 | else if (!isEscaped |
| 1670 | && !isQuoted && ((c == ';') || (c == ',') || (i == (header.length() - 1)))) |
| 1671 | { |
| 1672 | if (i == (header.length() - 1)) |
| 1673 | { |
| 1674 | value = header.substring(startIdx[0], header.length()); |
| 1675 | } |
| 1676 | else |
| 1677 | { |
| 1678 | value = header.substring(startIdx[0], i); |
| 1679 | } |
| 1680 | if (c == ',') |
| 1681 | { |
| 1682 | startIdx[0] = i - 1; |
| 1683 | } |
| 1684 | else |
| 1685 | { |
| 1686 | startIdx[0] = i + 1; |
| 1687 | } |
| 1688 | break; |
| 1689 | } |
| 1690 | |
| 1691 | isEscaped = (c == '\\'); |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1692 | } |
| 1693 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1694 | // Trim whitespace. |
| 1695 | name = name.trim(); |
| 1696 | value = value.trim(); |
| 1697 | |
| 1698 | // Remove quotes, if value is quoted. |
| 1699 | if (value.startsWith("\"") && value.endsWith("\"")) |
| 1700 | { |
| 1701 | value = value.substring(1, value.length() - 1); |
| 1702 | } |
| 1703 | |
| 1704 | // Check for dupes. |
| 1705 | if (clause.m_dirs.get(name) != null) |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1706 | { |
| 1707 | throw new IllegalArgumentException( |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1708 | "Duplicate directive '" + name + "' in: " + header); |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1709 | } |
| 1710 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1711 | clause.m_dirs.put(name, value); |
| 1712 | } |
| 1713 | |
| 1714 | private static void parseClauseAttribute( |
| 1715 | int[] startIdx, String header, ParsedHeaderClause clause) |
| 1716 | { |
| 1717 | String type = null; |
| 1718 | |
| 1719 | String name = parseClauseAttributeName(startIdx, header); |
| 1720 | char c = header.charAt(startIdx[0]); |
| 1721 | startIdx[0]++; |
| 1722 | if (c == ':') |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1723 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1724 | type = parseClauseAttributeType(startIdx, header); |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1725 | } |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1726 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1727 | String value = parseClauseAttributeValue(startIdx, header); |
| 1728 | |
| 1729 | // Trim whitespace. |
| 1730 | name = name.trim(); |
| 1731 | value = value.trim(); |
| 1732 | if (type != null) |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1733 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1734 | type = type.trim(); |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1735 | } |
| 1736 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1737 | // Remove quotes, if value is quoted. |
| 1738 | if (value.startsWith("\"") && value.endsWith("\"")) |
| 1739 | { |
| 1740 | value = value.substring(1, value.length() - 1); |
| 1741 | } |
| 1742 | |
| 1743 | // Check for dupes. |
| 1744 | if (clause.m_attrs.get(name) != null) |
| 1745 | { |
| 1746 | throw new IllegalArgumentException( |
| 1747 | "Duplicate attribute '" + name + "' in: " + header); |
| 1748 | } |
| 1749 | |
| 1750 | clause.m_attrs.put(name, value); |
| 1751 | if (type != null) |
| 1752 | { |
| 1753 | clause.m_types.put(name, type); |
| 1754 | } |
| 1755 | } |
| 1756 | |
| 1757 | private static String parseClauseAttributeName(int[] startIdx, String header) |
| 1758 | { |
| 1759 | for (int i = startIdx[0]; i < header.length(); i++) |
| 1760 | { |
| 1761 | char c = header.charAt(i); |
| 1762 | if ((c == '=') || (c == ':')) |
| 1763 | { |
| 1764 | String name = header.substring(startIdx[0], i); |
| 1765 | startIdx[0] = i; |
| 1766 | return name; |
| 1767 | } |
| 1768 | } |
| 1769 | return null; |
| 1770 | } |
| 1771 | |
| 1772 | private static String parseClauseAttributeType(int[] startIdx, String header) |
| 1773 | { |
| 1774 | for (int i = startIdx[0]; i < header.length(); i++) |
| 1775 | { |
| 1776 | char c = header.charAt(i); |
| 1777 | if (c == '=') |
| 1778 | { |
| 1779 | String type = header.substring(startIdx[0], i); |
| 1780 | startIdx[0] = i + 1; |
| 1781 | return type; |
| 1782 | } |
| 1783 | } |
| 1784 | return null; |
| 1785 | } |
| 1786 | |
| 1787 | private static String parseClauseAttributeValue(int[] startIdx, String header) |
| 1788 | { |
| 1789 | boolean isQuoted = false; |
| 1790 | boolean isEscaped = false; |
| 1791 | for (int i = startIdx[0]; i < header.length(); i++) |
| 1792 | { |
| 1793 | char c = header.charAt(i); |
| 1794 | if (!isEscaped && (c == '"')) |
| 1795 | { |
| 1796 | isQuoted = !isQuoted; |
| 1797 | } |
| 1798 | |
| 1799 | if (!isEscaped && |
| 1800 | !isQuoted && ((c == ';') || (c == ',') || (i == (header.length() - 1)))) |
| 1801 | { |
| 1802 | String value; |
| 1803 | if (i == (header.length() - 1)) |
| 1804 | { |
| 1805 | value = header.substring(startIdx[0], header.length()); |
| 1806 | } |
| 1807 | else |
| 1808 | { |
| 1809 | value = header.substring(startIdx[0], i); |
| 1810 | } |
| 1811 | if (c == ',') |
| 1812 | { |
| 1813 | startIdx[0] = i - 1; |
| 1814 | } |
| 1815 | else |
| 1816 | { |
| 1817 | startIdx[0] = i + 1; |
| 1818 | } |
| 1819 | return value; |
| 1820 | } |
| 1821 | |
| 1822 | isEscaped = (c == '\\'); |
| 1823 | } |
| 1824 | return null; |
| 1825 | } |
| 1826 | |
| 1827 | public static List<String> parseDelimitedString(String value, String delim) |
| 1828 | { |
| 1829 | return parseDelimitedString(value, delim, true); |
Richard S. Hall | 56b1194 | 2006-10-26 14:40:07 +0000 | [diff] [blame] | 1830 | } |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1831 | |
| 1832 | /** |
| 1833 | * Parses delimited string and returns an array containing the tokens. This |
| 1834 | * parser obeys quotes, so the delimiter character will be ignored if it is |
| 1835 | * inside of a quote. This method assumes that the quote character is not |
| 1836 | * included in the set of delimiter characters. |
| 1837 | * @param value the delimited string to parse. |
| 1838 | * @param delim the characters delimiting the tokens. |
Richard S. Hall | 3b78908 | 2011-01-19 17:58:17 +0000 | [diff] [blame] | 1839 | * @return a list of string or an empty list if there are none. |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1840 | **/ |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1841 | public static List<String> parseDelimitedString(String value, String delim, boolean trim) |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1842 | { |
| 1843 | if (value == null) |
| 1844 | { |
| 1845 | value = ""; |
| 1846 | } |
| 1847 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1848 | List<String> list = new ArrayList(); |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1849 | |
| 1850 | int CHAR = 1; |
| 1851 | int DELIMITER = 2; |
| 1852 | int STARTQUOTE = 4; |
| 1853 | int ENDQUOTE = 8; |
| 1854 | |
| 1855 | StringBuffer sb = new StringBuffer(); |
| 1856 | |
| 1857 | int expecting = (CHAR | DELIMITER | STARTQUOTE); |
Karl Pauls | 210a214 | 2007-02-12 23:37:08 +0000 | [diff] [blame] | 1858 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1859 | boolean isEscaped = false; |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1860 | for (int i = 0; i < value.length(); i++) |
| 1861 | { |
| 1862 | char c = value.charAt(i); |
| 1863 | |
| 1864 | boolean isDelimiter = (delim.indexOf(c) >= 0); |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1865 | |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1866 | if (c == '\\') |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1867 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1868 | isEscaped = true; |
| 1869 | continue; |
| 1870 | } |
| 1871 | |
| 1872 | if (isEscaped) |
| 1873 | { |
| 1874 | sb.append(c); |
| 1875 | } |
| 1876 | else if (isDelimiter && ((expecting & DELIMITER) > 0)) |
| 1877 | { |
| 1878 | if (trim) |
| 1879 | { |
| 1880 | list.add(sb.toString().trim()); |
| 1881 | } |
| 1882 | else |
| 1883 | { |
| 1884 | list.add(sb.toString()); |
| 1885 | } |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1886 | sb.delete(0, sb.length()); |
| 1887 | expecting = (CHAR | DELIMITER | STARTQUOTE); |
| 1888 | } |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1889 | else if ((c == '"') && ((expecting & STARTQUOTE) > 0)) |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1890 | { |
| 1891 | sb.append(c); |
| 1892 | expecting = CHAR | ENDQUOTE; |
| 1893 | } |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1894 | else if ((c == '"') && ((expecting & ENDQUOTE) > 0)) |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1895 | { |
| 1896 | sb.append(c); |
| 1897 | expecting = (CHAR | STARTQUOTE | DELIMITER); |
| 1898 | } |
| 1899 | else if ((expecting & CHAR) > 0) |
| 1900 | { |
| 1901 | sb.append(c); |
| 1902 | } |
| 1903 | else |
| 1904 | { |
| 1905 | throw new IllegalArgumentException("Invalid delimited string: " + value); |
| 1906 | } |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1907 | |
| 1908 | isEscaped = false; |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1909 | } |
| 1910 | |
| 1911 | if (sb.length() > 0) |
| 1912 | { |
Richard S. Hall | 831b771 | 2011-06-06 20:11:46 +0000 | [diff] [blame] | 1913 | if (trim) |
| 1914 | { |
| 1915 | list.add(sb.toString().trim()); |
| 1916 | } |
| 1917 | else |
| 1918 | { |
| 1919 | list.add(sb.toString()); |
| 1920 | } |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1921 | } |
| 1922 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1923 | return list; |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1924 | } |
| 1925 | |
| 1926 | /** |
| 1927 | * Parses native code manifest headers. |
| 1928 | * @param libStrs an array of native library manifest header |
| 1929 | * strings from the bundle manifest. |
| 1930 | * @return an array of <tt>LibraryInfo</tt> objects for the |
| 1931 | * passed in strings. |
| 1932 | **/ |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1933 | private static List<R4LibraryClause> parseLibraryStrings( |
| 1934 | Logger logger, List<String> libStrs) |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1935 | throws IllegalArgumentException |
| 1936 | { |
| 1937 | if (libStrs == null) |
| 1938 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1939 | return new ArrayList<R4LibraryClause>(0); |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1940 | } |
| 1941 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1942 | List<R4LibraryClause> libList = new ArrayList(libStrs.size()); |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1943 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1944 | for (int i = 0; i < libStrs.size(); i++) |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1945 | { |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1946 | R4LibraryClause clause = R4LibraryClause.parse(logger, libStrs.get(i)); |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1947 | libList.add(clause); |
| 1948 | } |
| 1949 | |
Richard S. Hall | 1320d47 | 2010-03-03 14:58:21 +0000 | [diff] [blame] | 1950 | return libList; |
Richard S. Hall | 7860542 | 2006-12-18 20:47:55 +0000 | [diff] [blame] | 1951 | } |
Richard S. Hall | 4ecc677 | 2011-05-17 21:20:32 +0000 | [diff] [blame] | 1952 | } |