/******************************************************************************* * Copyright (c) 2015 IBM Corp. * * Licensed 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 com.ibm.ws.massive.esa; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashSet; import java.util.Locale; import java.util.StringTokenizer; import java.util.zip.ZipException; import com.ibm.ws.massive.esa.internal.EsaManifest; import com.ibm.ws.massive.upload.RepositoryArchiveEntryNotFoundException; import com.ibm.ws.massive.upload.RepositoryArchiveIOException; import com.ibm.ws.massive.upload.RepositoryArchiveInvalidEntryException; import com.ibm.ws.massive.upload.RepositoryUploader; import com.ibm.ws.massive.upload.internal.MassiveUploader; import com.ibm.ws.repository.common.enums.AttachmentType; import com.ibm.ws.repository.common.enums.DisplayPolicy; import com.ibm.ws.repository.common.enums.InstallPolicy; import com.ibm.ws.repository.common.enums.LicenseType; import com.ibm.ws.repository.common.enums.Visibility; import com.ibm.ws.repository.connections.RepositoryConnection; import com.ibm.ws.repository.exceptions.RepositoryException; import com.ibm.ws.repository.exceptions.RepositoryResourceCreationException; import com.ibm.ws.repository.exceptions.RepositoryResourceUpdateException; import com.ibm.ws.repository.resources.EsaResource; import com.ibm.ws.repository.resources.internal.AppliesToProcessor; import com.ibm.ws.repository.resources.writeable.AttachmentResourceWritable; import com.ibm.ws.repository.resources.writeable.EsaResourceWritable; import com.ibm.ws.repository.resources.writeable.WritableResourceFactory; import com.ibm.ws.repository.strategies.writeable.UploadStrategy; /** * <p> * This class contains methods for working with ESAs inside MaaSive. * </p> */ public class MassiveEsa extends MassiveUploader implements RepositoryUploader<EsaResourceWritable> { /** * Construct a new instance and load all of the existing features inside MaaSive. * * @param userId The userId to use to connect to Massive * @param password The password to use to connect to Massive * @param apiKey The API key to use to connect to Massive * @throws RepositoryException */ public MassiveEsa(RepositoryConnection repoConnection) throws RepositoryException { super(repoConnection); } /** * This method will add a collection of ESAs into MaaSive * * @param esas The ESAs to add * @return the new {@link EsaResource}s added to massive (will not included any resources that * were modified as a result of this operation) * @throws ZipException * @throws RepositoryResourceCreationException * @throws RepositoryResourceUpdateException */ public Collection<EsaResource> addEsasToMassive(Collection<File> esas, UploadStrategy strategy) throws RepositoryException { Collection<EsaResource> resources = new HashSet<EsaResource>(); for (File esa : esas) { EsaResource resource = uploadFile(esa, strategy, null); resources.add(resource); } return resources; } /* * (non-Javadoc) * * @see com.ibm.ws.massive.upload.RepositoryUploader#canUploadFile(java.io.File) */ @Override public boolean canUploadFile(File assetFile) { return assetFile.getName().endsWith(".esa"); } /* * (non-Javadoc) * * @see com.ibm.ws.massive.upload.RepositoryUploader#uploadFile(java.io.File, * com.ibm.ws.massive.resources.UploadStrategy) */ @Override public EsaResourceWritable uploadFile(File esa, UploadStrategy strategy, String contentUrl) throws RepositoryException { ArtifactMetadata artifactMetadata = explodeArtifact(esa); // Read the meta data from the esa EsaManifest feature; try { feature = EsaManifest .constructInstance(esa); } catch (IOException e) { throw new RepositoryArchiveIOException(e.getMessage(), esa, e); } /* * First see if we already have this feature in MaaSive, note this means we can only have * one version of the asset in MaaSive at a time */ EsaResourceWritable resource = WritableResourceFactory.createEsa(repoConnection); String symbolicName = feature.getSymbolicName(); String version = feature.getVersion().toString(); // Massive assets are always English, find the best name String subsystemName = feature.getHeader("Subsystem-Name", Locale.ENGLISH); String shortName = feature.getIbmShortName(); String metadataName = artifactMetadata != null ? artifactMetadata.getName() : null; final String name; /* * We want to be able to override the name in the built ESA with a value supplied in the * metadata so use this in preference of what is in the ESA so that we can correct any typos * post-GM */ if (metadataName != null && !metadataName.isEmpty()) { name = metadataName; } else if (subsystemName != null && !subsystemName.isEmpty()) { name = subsystemName; } else if (shortName != null && !shortName.isEmpty()) { name = shortName; } else { // symbolic name is always set name = symbolicName; } resource.setName(name); String shortDescription = null; if (artifactMetadata != null) { shortDescription = artifactMetadata.getShortDescription(); resource.setDescription(artifactMetadata.getLongDescription()); } if (shortDescription == null) { shortDescription = feature.getHeader("Subsystem-Description", Locale.ENGLISH); } resource.setShortDescription(shortDescription); resource.setVersion(version); //Add icon files processIcons(esa, feature, resource); String provider = feature.getHeader("Subsystem-Vendor"); if (provider != null && !provider.isEmpty()) { resource.setProviderName(provider); } // Add custom attributes for WLP resource.setProvideFeature(symbolicName); resource.setAppliesTo(feature.getHeader("IBM-AppliesTo")); Visibility visibility = feature.getVisibility(); resource.setVisibility(visibility); /* * Two things affect the display policy - the visibility and the install policy. If a * private auto feature is set to manual install we need to make it visible so people know * that it exists and can be installed */ DisplayPolicy displayPolicy; DisplayPolicy webDisplayPolicy; if (visibility == Visibility.PUBLIC) { displayPolicy = DisplayPolicy.VISIBLE; webDisplayPolicy = DisplayPolicy.VISIBLE; } else { displayPolicy = DisplayPolicy.HIDDEN; webDisplayPolicy = DisplayPolicy.HIDDEN; } if (feature.isAutoFeature()) { resource.setProvisionCapability(feature.getHeader("IBM-Provision-Capability")); String IBMInstallPolicy = feature.getHeader("IBM-Install-Policy"); // Default InstallPolicy is set to MANUAL InstallPolicy installPolicy; if (IBMInstallPolicy != null && ("when-satisfied".equals(IBMInstallPolicy))) { installPolicy = InstallPolicy.WHEN_SATISFIED; } else { installPolicy = InstallPolicy.MANUAL; // As discussed above set the display policy to visible for any manual auto features displayPolicy = DisplayPolicy.VISIBLE; webDisplayPolicy = DisplayPolicy.VISIBLE; } resource.setInstallPolicy(installPolicy); } // if we are dealing with a beta feature hide it otherwise apply the // display policies from above if (isBeta(resource.getAppliesTo())) { resource.setWebDisplayPolicy(DisplayPolicy.HIDDEN); } else { resource.setWebDisplayPolicy(webDisplayPolicy); } // Always set displayPolicy resource.setDisplayPolicy(displayPolicy); // handle required iFixes String requiredFixes = feature.getHeader("IBM-Require-Fix"); if (requiredFixes != null && !requiredFixes.isEmpty()) { String[] fixes = requiredFixes.split(","); for (String fix : fixes) { fix = fix.trim(); if (!fix.isEmpty()) { resource.addRequireFix(fix); } } } resource.setShortName(shortName); // Calculate which features this relies on for (String requiredFeature : feature.getRequiredFeatures()) { resource.addRequireFeature(requiredFeature); } // feature.supersededBy is a comma-separated list of shortNames. Add // each of the elements to either supersededBy or supersededByOptional. String supersededBy = feature.getSupersededBy(); if (supersededBy != null && !supersededBy.trim().isEmpty()) { String[] supersededByArray = supersededBy.split(","); for (String f : supersededByArray) { // If one of the elements is surrounded by [square brackets] then we // strip the brackets off and treat it as optional if (f.startsWith("[")) { f = f.substring(1, f.length() - 1); resource.addSupersededByOptional(f); } else { resource.addSupersededBy(f); } } } String attachmentName = symbolicName + ".esa"; addContent(resource, esa, attachmentName, artifactMetadata, contentUrl); // Set the license type if we're using the feature terms agreement String subsystemLicense = feature.getHeader("Subsystem-License"); if (subsystemLicense != null && subsystemLicense.equals("http://www.ibm.com/licenses/wlp-featureterms-v1")) { resource.setLicenseType(LicenseType.UNSPECIFIED); } if (artifactMetadata != null) { attachLicenseData(artifactMetadata, resource); } // Now look for LI, LA files inside the .esa try { processLAandLI(esa, resource, feature); } catch (IOException e) { throw new RepositoryArchiveIOException(e.getMessage(), esa, e); } resource.setLicenseId(feature.getHeader("Subsystem-License")); // Publish to massive try { resource.uploadToMassive(strategy); } catch (RepositoryException re) { throw re; } return resource; } protected static boolean isBeta(String appliesTo) { // Use the appliesTo string to determine whether a feature is a Beta or a regular feature. // Beta features are of the format: // "com.ibm.websphere.appserver; productVersion=2014.8.0.0; productInstallType=Archive", if (appliesTo == null) { return false; } else { String regex = ".*productVersion=" + AppliesToProcessor.BETA_REGEX; boolean matches = appliesTo.matches(regex); return matches; } } private void processIcons(File esa, EsaManifest feature, EsaResourceWritable resource) throws RepositoryException { //checking icon file int size = 0; String current = ""; String sizeString = ""; String iconName = ""; String subsystemIcon = feature.getHeader("Subsystem-Icon"); if (subsystemIcon != null) { subsystemIcon = subsystemIcon.replaceAll("\\s", ""); StringTokenizer s = new StringTokenizer(subsystemIcon, ","); while (s.hasMoreTokens()) { current = s.nextToken(); if (current.contains(";")) { //if the icon has an associated size StringTokenizer t = new StringTokenizer(current, ";"); while (t.hasMoreTokens()) { sizeString = t.nextToken(); if (sizeString.contains("size=")) { String sizes[] = sizeString.split("size="); size = Integer.parseInt(sizes[sizes.length - 1]); } else { iconName = sizeString; } } } else { iconName = current; } File icon = this.extractFileFromArchive(esa.getAbsolutePath(), iconName).getExtractedFile(); if (icon.exists()) { AttachmentResourceWritable at = resource.addAttachment(icon, AttachmentType.THUMBNAIL); if (size != 0) { at.setImageDimensions(size, size); } } else { throw new RepositoryArchiveEntryNotFoundException("Icon does not exist", esa, iconName); } } } } @Override protected void checkRequiredProperties(ArtifactMetadata artifact) throws RepositoryArchiveInvalidEntryException { checkPropertySet(PROP_DESCRIPTION, artifact); } }