| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.cauldron.bld.config; |
| |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.cauldron.bld.config.IBldProject.IBldBundle; |
| import org.cauldron.bld.core.BldCore; |
| import org.cauldron.bld.core.internal.model.eclipse.SigilBundle; |
| import org.cauldron.bld.core.internal.model.osgi.BundleModelElement; |
| import org.cauldron.sigil.model.common.VersionRange; |
| import org.cauldron.sigil.model.eclipse.ISCAComposite; |
| import org.cauldron.sigil.model.eclipse.ISigilBundle; |
| import org.cauldron.sigil.model.osgi.IBundleModelElement; |
| import org.cauldron.sigil.model.osgi.IPackageExport; |
| import org.cauldron.sigil.model.osgi.IPackageImport; |
| import org.cauldron.sigil.model.osgi.IRequiredBundle; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.osgi.framework.Version; |
| |
| import aQute.lib.osgi.Constants; |
| |
| public class BldConverter { |
| private static final String classpathFormat = "<classpathentry kind=\"%s\" path=\"%s\"/>"; |
| private BldConfig config; |
| private Properties packageDefaults; |
| private TreeSet<String> packageWildDefaults; |
| |
| public BldConverter(BldConfig config) { |
| this.config = config; |
| } |
| |
| /** |
| * converts to an ISigilBundle. |
| * @param id |
| * @param bundle |
| * @return |
| */ |
| public ISigilBundle getBundle(String id, IBldBundle bundle) { |
| |
| ISigilBundle sigilBundle = new SigilBundle(); |
| IBundleModelElement info = new BundleModelElement(); |
| sigilBundle.setBundleInfo(info); |
| |
| // exports |
| // FIXME: UI doesn't understand export wildcard packages |
| for (IPackageExport export : bundle.getExports()) { |
| IPackageExport clone = (IPackageExport) export.clone(); |
| clone.setParent(null); |
| info.addExport(clone); |
| } |
| |
| // imports |
| for (IPackageImport import1 : bundle.getImports()) { |
| IPackageImport clone = (IPackageImport) import1.clone(); |
| clone.setParent(null); |
| info.addImport(clone); |
| } |
| |
| // requires |
| for (IRequiredBundle require : bundle.getRequires()) { |
| IRequiredBundle clone = (IRequiredBundle) require.clone(); |
| clone.setParent(null); |
| info.addRequiredBundle(clone); |
| } |
| |
| // fragment |
| IRequiredBundle fragment = bundle.getFragmentHost(); |
| if (fragment != null) { |
| info.setFragmentHost(fragment); |
| } |
| |
| // contents |
| for (String pkg : bundle.getContents()) { |
| sigilBundle.addPackage(pkg); |
| } |
| |
| // downloads |
| for (String pkg : bundle.getDownloadContents()) { |
| sigilBundle.addDownloadPackage(pkg); |
| } |
| |
| // sources |
| for (String source : config.getList(null, BldConfig.L_SRC_CONTENTS) ) { |
| sigilBundle.addClasspathEntry(String.format(classpathFormat, "src", source)); |
| } |
| |
| // libs |
| Map<String, Map<String, String>> libs = bundle.getLibs(); |
| |
| for (String path : libs.keySet()) { |
| Map<String, String> attr = libs.get(path); |
| String kind = attr.get(BldAttr.KIND_ATTRIBUTE); |
| String publish = attr.get(BldAttr.PUBLISH_ATTRIBUTE); |
| |
| if (publish != null) { |
| // FIXME: UI doesn't understand publish=name |
| BldCore.error("Can't convert -libs publish=" + publish); |
| continue; |
| } |
| |
| if ("classpath".equals(kind)) { |
| sigilBundle.addClasspathEntry(String.format(classpathFormat, "lib", path)); |
| } else { |
| BldCore.error("Can't convert -libs kind=" + kind); |
| } |
| } |
| |
| // resources |
| // FIXME: UI doesn't support -resources: path1=path2 |
| Map<String, String> resources = bundle.getResources(); |
| for (String resource : resources.keySet()) { |
| String fsPath = resources.get(resource); |
| if (!"".equals(fsPath)) { |
| BldCore.error("FIXME: can't convert resource: " + resource + "=" + fsPath); |
| } |
| sigilBundle.addSourcePath(new Path(resource)); |
| } |
| |
| //////////////////// |
| // simple headers |
| |
| info.setSymbolicName(bundle.getSymbolicName()); |
| |
| info.setVersion(Version.parseVersion(bundle.getVersion())); |
| |
| String activator = bundle.getActivator(); |
| if (activator != null) |
| info.setActivator(activator); |
| |
| Properties headers = config.getProps(id, BldConfig.P_HEADER); |
| String header; |
| |
| header = headers.getProperty("CATEGORY"); |
| if (header != null) |
| info.setCategory(header); |
| |
| header = headers.getProperty(Constants.BUNDLE_CONTACTADDRESS); |
| if (header != null) |
| info.setContactAddress(header); |
| |
| header = headers.getProperty(Constants.BUNDLE_COPYRIGHT); |
| if (header != null) |
| info.setCopyright(header); |
| |
| header = headers.getProperty(Constants.BUNDLE_DESCRIPTION); |
| if (header != null) |
| info.setDescription(header); |
| |
| header = headers.getProperty(Constants.BUNDLE_VENDOR); |
| if (header != null) |
| info.setVendor(header); |
| |
| header = headers.getProperty(Constants.BUNDLE_NAME); |
| if (header != null) |
| info.setName(header); |
| |
| header = headers.getProperty(Constants.BUNDLE_DOCURL); |
| if (header != null) |
| info.setDocURI(URI.create(header)); |
| |
| header = headers.getProperty(Constants.BUNDLE_LICENSE); |
| if (header != null) |
| info.setDocURI(URI.create(header)); |
| |
| return sigilBundle; |
| } |
| |
| private VersionRange defaultVersion(VersionRange current, String defaultRange) { |
| if (current.equals(VersionRange.ANY_VERSION) || |
| current.equals(VersionRange.parseVersionRange(defaultRange))) { |
| return null; |
| } |
| return current; |
| } |
| |
| // FIXME - copied from BldProject |
| private String getDefaultPackageVersion(String name) { |
| if (packageDefaults == null) { |
| packageDefaults = config.getProps(null, BldConfig.P_PACKAGE_VERSION); |
| packageWildDefaults = new TreeSet<String>(); |
| |
| for (Object key : packageDefaults.keySet()) { |
| String pkg = (String)key; |
| if (pkg.endsWith("*")) { |
| packageWildDefaults.add(pkg.substring(0, pkg.length() - 1)); |
| } |
| } |
| } |
| |
| String version = packageDefaults.getProperty(name); |
| |
| if (version == null) { |
| for (String pkg : packageWildDefaults) { |
| if (name.startsWith(pkg)) { |
| version = packageDefaults.getProperty(pkg + "*"); |
| // break; -- don't break, as we want the longest match |
| } |
| } |
| } |
| |
| return version; |
| } |
| |
| |
| /** |
| * converts from an ISigilBundle. |
| * |
| * @param id |
| * @param bundle |
| */ |
| public void setBundle(String id, ISigilBundle bundle) { |
| IBundleModelElement info = bundle.getBundleInfo(); |
| String bundleVersion = config.getString(id, BldConfig.S_VERSION); |
| |
| // exports |
| Map<String, Map<String, String>> exports = new TreeMap<String, Map<String,String>>(); |
| for (IPackageExport export : info.getExports()) { |
| Map<String, String> map2 = new TreeMap<String, String>(); |
| String version = export.getVersion().toString(); |
| if (!version.equals(bundleVersion)) |
| map2.put(BldAttr.VERSION_ATTRIBUTE, version); |
| exports.put(export.getPackageName(), map2); |
| } |
| |
| if (!exports.isEmpty() || !config.getMap(id, BldConfig.M_EXPORTS).isEmpty()) { |
| config.setMap(id, BldConfig.M_EXPORTS, exports); |
| } |
| |
| // imports |
| Map<String, Map<String, String>> imports = new TreeMap<String, Map<String,String>>(); |
| |
| // FIXME: default version logic is wrong here |
| // if the version to be saved is the same as the default version, |
| // then we should _remove_ the version from the value being saved, |
| // since config.getMap() does not apply default versions. |
| for (IPackageImport import1 : info.getImports()) { |
| Map<String, String> map2 = new TreeMap<String, String>(); |
| String name = import1.getPackageName(); |
| VersionRange versions = defaultVersion(import1.getVersions(), getDefaultPackageVersion(name)); |
| |
| boolean isDependency = import1.isDependency(); |
| Map<String, String> selfImport = exports.get(name); |
| |
| if (selfImport != null) { |
| // avoid saving self-import attributes, e.g. |
| // org.cauldron.newton.example.fractal.engine;resolve=auto;version=1.0.0 |
| isDependency = true; |
| |
| if (versions != null) { |
| String exportVersion = selfImport.get(BldAttr.VERSION_ATTRIBUTE); |
| if (exportVersion == null) |
| exportVersion = bundleVersion; |
| |
| if (exportVersion.equals(versions.toString())) { |
| versions = null; |
| } |
| } |
| } |
| |
| if (versions != null) { |
| map2.put(BldAttr.VERSION_ATTRIBUTE, versions.toString()); |
| } |
| |
| if (import1.isOptional()) { |
| map2.put(BldAttr.RESOLUTION_ATTRIBUTE, BldAttr.RESOLUTION_OPTIONAL); |
| } |
| |
| String resolve = BldProject.getResolve(import1, isDependency); |
| if (resolve != null) |
| map2.put(BldAttr.RESOLVE_ATTRIBUTE, resolve); |
| |
| imports.put(name, map2); |
| } |
| if (!imports.isEmpty() || !config.getMap(id, BldConfig.M_IMPORTS).isEmpty()) { |
| config.setMap(id, BldConfig.M_IMPORTS, imports); |
| } |
| |
| // requires |
| Properties defaultBundles = config.getProps(null, BldConfig.P_BUNDLE_VERSION); |
| Map<String, Map<String, String>> requires = new TreeMap<String, Map<String,String>>(); |
| |
| for (IRequiredBundle require : info.getRequiredBundles()) { |
| Map<String, String> map2 = new TreeMap<String, String>(); |
| String name = require.getSymbolicName(); |
| VersionRange versions = defaultVersion(require.getVersions(), defaultBundles.getProperty(name)); |
| if (versions != null) |
| map2.put(BldAttr.VERSION_ATTRIBUTE, versions.toString()); |
| requires.put(name, map2); |
| } |
| if (!requires.isEmpty() || !config.getMap(id, BldConfig.M_REQUIRES).isEmpty()) { |
| config.setMap(id, BldConfig.M_REQUIRES, requires); |
| } |
| |
| // fragment |
| Map<String, Map<String, String>> fragments = new TreeMap<String, Map<String,String>>(); |
| IRequiredBundle fragment = info.getFragmentHost(); |
| if (fragment != null) { |
| Map<String, String> map2 = new TreeMap<String, String>(); |
| String name = fragment.getSymbolicName(); |
| VersionRange versions = defaultVersion(fragment.getVersions(), defaultBundles.getProperty(name)); |
| if (versions != null) |
| map2.put(BldAttr.VERSION_ATTRIBUTE, versions.toString()); |
| fragments.put(name, map2); |
| } |
| if (!fragments.isEmpty() || !config.getMap(id, BldConfig.M_FRAGMENT).isEmpty()) { |
| config.setMap(id, BldConfig.M_FRAGMENT, fragments); |
| } |
| |
| // contents |
| List<String> contents = new ArrayList<String>(); |
| for (String pkg : bundle.getPackages()) { |
| contents.add(pkg); |
| } |
| if (!contents.isEmpty() || !config.getList(id, BldConfig.L_CONTENTS).isEmpty()) { |
| config.setList(id, BldConfig.L_CONTENTS, contents); |
| } |
| |
| // dl contents |
| List<String> dlcontents = new ArrayList<String>(); |
| for (String pkg : bundle.getDownloadPackages()) { |
| dlcontents.add(pkg); |
| } |
| if (!dlcontents.isEmpty() || !config.getList(id, BldConfig.L_DL_CONTENTS).isEmpty()) { |
| config.setList(id, BldConfig.L_DL_CONTENTS, dlcontents); |
| } |
| |
| // libs |
| Map<String, Map<String, String>> libs = new TreeMap<String, Map<String,String>>(); |
| List<String> sources = new ArrayList<String>(); |
| |
| // classpathEntries map to -libs or -sources |
| for (String entry : bundle.getClasspathEntrys()) { |
| // <classpathentry kind="lib" path="lib/dependee.jar"/> |
| // <classpathentry kind="src" path="src"/> |
| final String regex = ".* kind=\"([^\"]+)\" path=\"([^\"]+)\".*"; |
| Pattern pattern = Pattern.compile(regex); |
| Matcher matcher = pattern.matcher(entry); |
| if (matcher.matches()) { |
| String kind = matcher.group(1); |
| String path = matcher.group(2); |
| if (kind.equals("lib")) { |
| Map<String, String> map2 = new TreeMap<String, String>(); |
| map2.put(BldAttr.KIND_ATTRIBUTE, "classpath"); |
| libs.put(path, map2); |
| } else if (kind.equals("src")) { |
| sources.add(path); |
| } else { |
| BldCore.error("unknown classpathentry kind=" + kind); |
| } |
| } else { |
| BldCore.error("can't match classpathEntry in: " + entry); |
| } |
| } |
| |
| if (!libs.isEmpty() || !config.getMap(id, BldConfig.M_LIBS).isEmpty()) { |
| config.setMap(id, BldConfig.M_LIBS, libs); |
| } |
| |
| if (!sources.isEmpty() || !config.getList(id, BldConfig.L_SRC_CONTENTS).isEmpty()) { |
| config.setList(id, BldConfig.L_SRC_CONTENTS, sources); |
| } |
| |
| // composites |
| ArrayList<String> composites = new ArrayList<String>(); |
| for (ISCAComposite composite : bundle.getComposites()) { |
| String path = composite.getLocation().toString(); |
| // TODO relativize |
| composites.add(path); |
| } |
| |
| if (!composites.isEmpty() || !config.getList(id, BldConfig.L_COMPOSITES).isEmpty()) { |
| Collections.sort(composites); |
| config.setList(id, BldConfig.L_COMPOSITES, composites); |
| } |
| |
| // resources |
| ArrayList<String> resources = new ArrayList<String>(); |
| for (IPath ipath : bundle.getSourcePaths()) { |
| resources.add(ipath.toString()); |
| } |
| |
| if (!resources.isEmpty() || !config.getList(id, BldConfig.L_RESOURCES).isEmpty()) { |
| Collections.sort(resources); |
| config.setList(id, BldConfig.L_RESOURCES, resources); |
| } |
| |
| if (info.getSourceLocation() != null) { |
| BldCore.error("SourceLocation conversion not yet implemented."); |
| } |
| |
| if (!info.getLibraryImports().isEmpty()) { |
| BldCore.error("LibraryImports conversion not yet implemented."); |
| } |
| |
| //////////////////// |
| // simple headers |
| |
| List<String> ids = config.getList(null, BldConfig.C_BUNDLES); |
| String idBsn = id != null ? id : ids.get(0); |
| String oldBsn = config.getString(id, BldConfig.S_SYM_NAME); |
| String bsn = info.getSymbolicName(); |
| |
| if (!bsn.equals(idBsn) || oldBsn != null) |
| config.setString(id, BldConfig.S_SYM_NAME, bsn); |
| |
| String version = info.getVersion().toString(); |
| if (version != null) |
| config.setString(id, BldConfig.S_VERSION, version); |
| |
| String activator = info.getActivator(); |
| if (activator != null) |
| config.setString(id, BldConfig.S_ACTIVATOR, activator); |
| |
| Properties headers = config.getProps(null, BldConfig.P_HEADER); |
| |
| setHeader(headers, id, "CATEGORY", info.getCategory()); |
| setHeader(headers, id, Constants.BUNDLE_CONTACTADDRESS, info.getContactAddress()); |
| setHeader(headers, id, Constants.BUNDLE_COPYRIGHT, info.getCopyright()); |
| setHeader(headers, id, Constants.BUNDLE_DESCRIPTION, info.getDescription()); |
| setHeader(headers, id, Constants.BUNDLE_VENDOR, info.getVendor()); |
| setHeader(headers, id, Constants.BUNDLE_NAME, info.getName()); |
| |
| if (info.getDocURI() != null) |
| config.setProp(id, BldConfig.P_HEADER, Constants.BUNDLE_DOCURL, info.getDocURI().toString()); |
| |
| if (info.getLicenseURI() != null) |
| config.setProp(id, BldConfig.P_HEADER, Constants.BUNDLE_LICENSE, info.getLicenseURI().toString()); |
| } |
| |
| private void setHeader(Properties headers, String id, String key, String value) { |
| if (value == null) |
| value = ""; |
| if (!value.equals(headers.getProperty(key, ""))) |
| config.setProp(id, BldConfig.P_HEADER, key, value); |
| } |
| } |