| /******************************************************************************* |
| * Copyright (c) 2008, 2012 Code 9 and others. All rights reserved. This |
| * program and the accompanying materials are made available under the terms of |
| * the Eclipse Public License v1.0 which accompanies this distribution, and is |
| * available at http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Code 9 - initial API and implementation |
| * IBM - ongoing development |
| * SAP AG - ongoing development |
| ******************************************************************************/ |
| package org.eclipse.equinox.p2.publisher.actions; |
| |
| import java.io.*; |
| import java.net.URL; |
| import java.util.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; |
| import org.eclipse.equinox.internal.p2.metadata.ArtifactKey; |
| import org.eclipse.equinox.internal.p2.publisher.Activator; |
| import org.eclipse.equinox.internal.p2.publisher.Messages; |
| import org.eclipse.equinox.p2.metadata.*; |
| import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; |
| import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitFragmentDescription; |
| import org.eclipse.equinox.p2.metadata.Version; |
| import org.eclipse.equinox.p2.metadata.VersionRange; |
| import org.eclipse.equinox.p2.publisher.*; |
| import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; |
| import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; |
| import org.eclipse.osgi.util.ManifestElement; |
| import org.eclipse.osgi.util.NLS; |
| import org.osgi.framework.*; |
| |
| public class JREAction extends AbstractPublisherAction { |
| private static final String DEFAULT_JRE_NAME = "a.jre"; //$NON-NLS-1$ |
| private static final Version DEFAULT_JRE_VERSION = Version.parseVersion("1.6"); //$NON-NLS-1$ |
| private static final String DEFAULT_PROFILE = "JavaSE-1.6"; //$NON-NLS-1$ |
| private static final String PROFILE_LOCATION = "jre.action.profile.location"; //$NON-NLS-1$ |
| private static final String PROFILE_NAME = "osgi.java.profile.name"; //$NON-NLS-1$ |
| private static final String PROFILE_TARGET_VERSION = "org.eclipse.jdt.core.compiler.codegen.targetPlatform"; //$NON-NLS-1$ |
| private static final String PROFILE_SYSTEM_PACKAGES = "org.osgi.framework.system.packages"; //$NON-NLS-1$ |
| |
| public static final String NAMESPACE_OSGI_EE = "osgi.ee"; //$NON-NLS-1$ |
| |
| private File jreLocation; |
| private String environment; |
| private Map<String, String> profileProperties; |
| private MultiStatus resultStatus; |
| |
| public JREAction(File location) { |
| this.jreLocation = location; |
| } |
| |
| public JREAction(String environment) { |
| this.environment = environment; |
| } |
| |
| @Override |
| public IStatus perform(IPublisherInfo publisherInfo, IPublisherResult results, IProgressMonitor monitor) { |
| String problemMessage = NLS.bind(Messages.message_problemsWhilePublishingEE, jreLocation != null ? jreLocation : environment); |
| resultStatus = new MultiStatus(Activator.ID, 0, problemMessage, null); |
| |
| initialize(publisherInfo); |
| IArtifactDescriptor artifact = createJREData(results); |
| if (artifact != null) |
| publishArtifact(artifact, new File[] {jreLocation}, null, publisherInfo, createRootPrefixComputer(jreLocation)); |
| |
| if (resultStatus.isOK()) |
| return Status.OK_STATUS; |
| return resultStatus; |
| } |
| |
| private static Status newErrorStatus(String message, Exception exception) { |
| return new Status(IStatus.ERROR, Activator.ID, message, exception); |
| } |
| |
| private static Status newWarningStatus(String message) { |
| return new Status(IStatus.WARNING, Activator.ID, message, null); |
| } |
| |
| /** |
| * Creates IUs and artifact descriptors for the JRE. The resulting IUs are added |
| * to the given set, and the resulting artifact descriptor, if any, is returned. |
| * If the jreLocation is <code>null</code>, default information is generated. |
| */ |
| protected IArtifactDescriptor createJREData(IPublisherResult results) { |
| InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); |
| iu.setSingleton(false); |
| iu.setId(DEFAULT_JRE_NAME); |
| iu.setVersion(DEFAULT_JRE_VERSION); |
| iu.setTouchpointType(PublisherHelper.TOUCHPOINT_NATIVE); |
| |
| generateJREIUData(iu); |
| |
| InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); |
| String configId = "config." + iu.getId();//$NON-NLS-1$ |
| cu.setId(configId); |
| cu.setVersion(iu.getVersion()); |
| VersionRange range = iu.getVersion() == Version.emptyVersion ? VersionRange.emptyRange : new VersionRange(iu.getVersion(), true, Version.MAX_VERSION, true); |
| cu.setHost(new IRequirement[] {MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, iu.getId(), range, null, false, false)}); |
| cu.setProperty(InstallableUnitDescription.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); |
| cu.setCapabilities(new IProvidedCapability[] {PublisherHelper.createSelfCapability(configId, iu.getVersion())}); |
| cu.setTouchpointType(PublisherHelper.TOUCHPOINT_NATIVE); |
| Map<String, String> touchpointData = new HashMap<>(); |
| |
| if (jreLocation == null || !jreLocation.isDirectory()) { |
| touchpointData.put("install", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); |
| results.addIU(MetadataFactory.createInstallableUnit(iu), IPublisherResult.ROOT); |
| results.addIU(MetadataFactory.createInstallableUnit(cu), IPublisherResult.ROOT); |
| return null; |
| } |
| |
| //Generate artifact for JRE |
| IArtifactKey key = new ArtifactKey(PublisherHelper.BINARY_ARTIFACT_CLASSIFIER, iu.getId(), iu.getVersion()); |
| iu.setArtifacts(new IArtifactKey[] {key}); |
| results.addIU(MetadataFactory.createInstallableUnit(iu), IPublisherResult.ROOT); |
| |
| //Create config info for the CU |
| String configurationData = "unzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$ |
| touchpointData.put("install", configurationData); //$NON-NLS-1$ |
| String unConfigurationData = "cleanupzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$ |
| touchpointData.put("uninstall", unConfigurationData); //$NON-NLS-1$ |
| cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); |
| results.addIU(MetadataFactory.createInstallableUnit(cu), IPublisherResult.ROOT); |
| |
| //Create the artifact descriptor |
| return PublisherHelper.createArtifactDescriptor(info, key, jreLocation); |
| } |
| |
| private List<IProvidedCapability> generateJRECapability(String id, Version version) { |
| if (profileProperties == null) |
| return Collections.emptyList(); |
| |
| List<IProvidedCapability> result = new ArrayList<>(); |
| result.add(PublisherHelper.createSelfCapability(id, version)); |
| generateProvidedPackages(result); |
| generateOsgiEESystemCapabilities(result); |
| return result; |
| } |
| |
| private void generateProvidedPackages(List<IProvidedCapability> result) { |
| String packages = profileProperties.get(PROFILE_SYSTEM_PACKAGES); |
| if (packages != null && (packages.trim().length() > 0)) { |
| |
| try { |
| ManifestElement[] jrePackages = ManifestElement.parseHeader(PROFILE_SYSTEM_PACKAGES, packages); |
| for (int i = 0; i < jrePackages.length; i++) { |
| String packageName = jrePackages[i].getValue(); |
| Version packageVersion = Version.create(jrePackages[i].getAttribute("version")); //$NON-NLS-1$ |
| result.add(MetadataFactory.createProvidedCapability(PublisherHelper.CAPABILITY_NS_JAVA_PACKAGE, packageName, packageVersion)); |
| } |
| } catch (BundleException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| void generateOsgiEESystemCapabilities(List<IProvidedCapability> result) { |
| String message = NLS.bind(Messages.message_problemsWhileParsingProfileProperty, Constants.FRAMEWORK_SYSTEMCAPABILITIES); |
| MultiStatus parsingStatus = new MultiStatus(Activator.ID, 0, message, null); |
| |
| String systemCapabilities = profileProperties.get(Constants.FRAMEWORK_SYSTEMCAPABILITIES); |
| parseSystemCapabilities(systemCapabilities, parsingStatus, result); |
| |
| // result contains the valid entries, parsingStatus the invalid entries |
| if (!parsingStatus.isOK()) |
| resultStatus.add(parsingStatus); |
| } |
| |
| static void parseSystemCapabilities(String systemCapabilities, MultiStatus parsingStatus, List<IProvidedCapability> parsingResult) { |
| if (systemCapabilities == null || (systemCapabilities.trim().length() == 0)) { |
| return; |
| } |
| |
| try { |
| ManifestElement[] eeEntries = ManifestElement.parseHeader(Constants.FRAMEWORK_SYSTEMCAPABILITIES, systemCapabilities); |
| parseSystemCapabilities(eeEntries, parsingStatus, parsingResult); |
| |
| } catch (BundleException e) { |
| parsingStatus.add(newErrorStatus(e.getLocalizedMessage(), e)); |
| } |
| } |
| |
| private static void parseSystemCapabilities(ManifestElement[] systemCapabilities, MultiStatus parsingStatus, List<IProvidedCapability> parsingResult) { |
| for (int capabilityIx = 0; capabilityIx < systemCapabilities.length; capabilityIx++) { |
| ManifestElement systemCapability = systemCapabilities[capabilityIx]; |
| |
| // this is general manifest syntax: a "manifest element" can have multiple "value components" -> all attributes apply to each value component (=namespace) |
| String[] namespaces = systemCapability.getValueComponents(); |
| for (int namespaceIx = 0; namespaceIx < namespaces.length; namespaceIx++) { |
| String namespace = namespaces[namespaceIx]; |
| |
| if (NAMESPACE_OSGI_EE.equals(namespace)) { // this is the OSGi capability namespace "osgi.ee" |
| parseEECapability(systemCapability, parsingStatus, parsingResult); |
| |
| } else { |
| parsingStatus.add(newWarningStatus(NLS.bind(Messages.message_eeIgnoringNamespace, namespace))); |
| continue; |
| } |
| } |
| } |
| } |
| |
| private static void parseEECapability(ManifestElement eeCapability, MultiStatus parsingStatus, List<IProvidedCapability> parsingResult) { |
| String eeName = eeCapability.getAttribute(NAMESPACE_OSGI_EE); // this is an attribute required for capabilities in the "osgi.ee" namespace |
| if (eeName == null) { |
| parsingStatus.add(newErrorStatus(NLS.bind(Messages.message_eeMissingNameAttribute, eeCapability), null)); |
| return; |
| } |
| |
| String[] eeVersions = parseEECapabilityVersion(eeCapability, parsingStatus); |
| if (eeVersions == null) { |
| // status was already updated by parse method |
| return; |
| } |
| |
| for (int versionIx = 0; versionIx < eeVersions.length; versionIx++) { |
| String rawVersion = eeVersions[versionIx]; |
| try { |
| Version parsedVersion = Version.parseVersion(rawVersion); |
| |
| // complete record -> store |
| Map<String, Object> capAttrs = new HashMap<String, Object>(); |
| capAttrs.put(NAMESPACE_OSGI_EE, eeName); |
| capAttrs.put("version", parsedVersion); |
| |
| parsingResult.add(MetadataFactory.createProvidedCapability(NAMESPACE_OSGI_EE, capAttrs)); |
| |
| } catch (IllegalArgumentException e) { |
| parsingStatus.add(newErrorStatus(NLS.bind(Messages.message_eeInvalidVersionAttribute, rawVersion), e)); |
| } |
| } |
| } |
| |
| private static String[] parseEECapabilityVersion(ManifestElement eeCapability, MultiStatus parsingStatus) { |
| String singleVersion = eeCapability.getAttribute("version:Version"); //$NON-NLS-1$ |
| String[] multipleVersions = ManifestElement.getArrayFromList(eeCapability.getAttribute("version:List<Version>")); //$NON-NLS-1$ |
| |
| if (singleVersion == null && multipleVersions == null) { |
| parsingStatus.add(newErrorStatus(NLS.bind(Messages.message_eeMissingVersionAttribute, eeCapability), null)); |
| return null; |
| |
| } else if (singleVersion == null) { |
| return multipleVersions; |
| |
| } else if (multipleVersions == null) { |
| return new String[] {singleVersion}; |
| |
| } else { |
| parsingStatus.add(newErrorStatus(NLS.bind(Messages.message_eeDuplicateVersionAttribute, eeCapability), null)); |
| return null; |
| } |
| } |
| |
| private void generateJREIUData(InstallableUnitDescription iu) { |
| if (profileProperties == null || profileProperties.size() == 0) |
| return; //got nothing |
| |
| String profileLocation = profileProperties.get(PROFILE_LOCATION); |
| |
| String profileName = profileLocation != null ? new Path(profileLocation).lastSegment() : profileProperties.get(PROFILE_NAME); |
| if (profileName.endsWith(".profile")) //$NON-NLS-1$ |
| profileName = profileName.substring(0, profileName.length() - 8); |
| Version version = null; |
| int idx = profileName.indexOf('-'); |
| if (idx != -1) { |
| try { |
| version = Version.parseVersion(profileName.substring(idx + 1)); |
| } catch (IllegalArgumentException e) { |
| //ignore |
| } |
| profileName = profileName.substring(0, idx); |
| } |
| if (version == null) { |
| try { |
| String targetVersion = profileProperties.get(PROFILE_TARGET_VERSION); |
| version = targetVersion != null ? Version.parseVersion(targetVersion) : null; |
| } catch (IllegalArgumentException e) { |
| //ignore |
| } |
| } |
| |
| if (version == null) |
| version = DEFAULT_JRE_VERSION; |
| |
| iu.setVersion(version); |
| |
| profileName = profileName.replace('-', '.'); |
| profileName = profileName.replace('/', '.'); |
| profileName = profileName.replace('_', '.'); |
| iu.setId("a.jre." + profileName.toLowerCase()); //$NON-NLS-1$ |
| |
| List<IProvidedCapability> capabilities = generateJRECapability(iu.getId(), iu.getVersion()); |
| iu.addProvidedCapabilities(capabilities); |
| } |
| |
| private void initialize(IPublisherInfo publisherInfo) { |
| this.info = publisherInfo; |
| |
| if (jreLocation != null) { |
| |
| File javaProfile = null; |
| |
| if (jreLocation.isDirectory()) { |
| //Look for a JRE profile file to set version and capabilities |
| File[] profiles = jreLocation.listFiles((FileFilter) pathname -> pathname.getAbsolutePath().endsWith(".profile")); |
| if (profiles != null && profiles.length > 0) { |
| javaProfile = profiles[0]; |
| } |
| } else if (jreLocation.isFile()) |
| javaProfile = jreLocation; |
| else |
| // jreLocation file does not exist |
| throw new IllegalArgumentException(NLS.bind(Messages.exception_nonExistingJreLocationFile, jreLocation.getAbsolutePath())); |
| |
| profileProperties = loadProfile(javaProfile); |
| } |
| if (profileProperties == null) { |
| String profileFile = (environment != null ? environment : DEFAULT_PROFILE).replace('/', '_') + ".profile"; //$NON-NLS-1$ |
| URL profileURL = getResouceFromSystemBundle(profileFile); |
| profileProperties = loadProfile(profileURL); |
| } |
| } |
| |
| private static URL getResouceFromSystemBundle(String entry) { |
| // get resource from system bundle which is typically on the Java boot classpath |
| ClassLoader loader = FrameworkUtil.class.getClassLoader(); |
| return loader == null ? ClassLoader.getSystemResource(entry) : loader.getResource(entry); |
| } |
| |
| private Map<String, String> loadProfile(File profileFile) { |
| if (profileFile == null || !profileFile.exists()) |
| return null; |
| |
| try { |
| InputStream stream = new BufferedInputStream(new FileInputStream(profileFile)); |
| Map<String, String> properties = loadProfile(stream); |
| if (properties != null) |
| properties.put(PROFILE_LOCATION, profileFile.getAbsolutePath()); |
| return properties; |
| } catch (FileNotFoundException e) { |
| //null |
| } |
| return null; |
| } |
| |
| private Map<String, String> loadProfile(URL profileURL) { |
| if (profileURL == null) |
| return null; |
| |
| try { |
| InputStream stream = profileURL.openStream(); |
| return loadProfile(stream); |
| } catch (IOException e) { |
| //null |
| } |
| return null; |
| } |
| |
| /** |
| * Always closes the stream when done |
| */ |
| private Map<String, String> loadProfile(InputStream stream) { |
| if (stream != null) { |
| try { |
| return CollectionUtils.loadProperties(stream); |
| } catch (IOException e) { |
| return null; |
| } finally { |
| try { |
| stream.close(); |
| } catch (IOException e) { |
| // error |
| } |
| } |
| } |
| return null; |
| } |
| } |