/******************************************************************************* * 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.repository.resources.internal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import com.ibm.ws.repository.common.enums.DisplayPolicy; import com.ibm.ws.repository.common.enums.DownloadPolicy; import com.ibm.ws.repository.common.enums.FilterPredicate; import com.ibm.ws.repository.common.enums.FilterableAttribute; import com.ibm.ws.repository.common.enums.InstallPolicy; import com.ibm.ws.repository.common.enums.ResourceType; import com.ibm.ws.repository.common.enums.Visibility; import com.ibm.ws.repository.connections.RepositoryConnection; import com.ibm.ws.repository.exceptions.RepositoryBackendException; import com.ibm.ws.repository.exceptions.RepositoryResourceCreationException; import com.ibm.ws.repository.resources.RepositoryResource; import com.ibm.ws.repository.resources.writeable.EsaResourceWritable; import com.ibm.ws.repository.transport.model.AppliesToFilterInfo; import com.ibm.ws.repository.transport.model.Asset; import com.ibm.ws.repository.transport.model.JavaSEVersionRequirements; import com.ibm.ws.repository.transport.model.WlpInformation; public class EsaResourceImpl extends RepositoryResourceImpl implements EsaResourceWritable { /** * ---------------------------------------------------------------------------------------------------- * INSTANCE METHODS * ---------------------------------------------------------------------------------------------------- */ /** * Constructor - requires connection info * */ public EsaResourceImpl(RepositoryConnection repoConnection) { this(repoConnection, null); } public EsaResourceImpl(RepositoryConnection repoConnection, Asset ass) { super(repoConnection, ass); if (ass == null) { setType(ResourceType.FEATURE); setDownloadPolicy(DownloadPolicy.INSTALLER); setInstallPolicy(InstallPolicy.MANUAL); } } /** {@inheritDoc} */ @Override public void setProvideFeature(String feature) { if (_asset.getWlpInformation().getProvideFeature() != null) { _asset.getWlpInformation().setProvideFeature(null); } _asset.getWlpInformation().addProvideFeature(feature); } /** {@inheritDoc} */ @Override public String getProvideFeature() { Collection<String> provideFeatures = _asset.getWlpInformation() .getProvideFeature(); if (provideFeatures == null || provideFeatures.isEmpty()) { return null; } else { return provideFeatures.iterator().next(); } } /* * Uses the required features information to calculate a list of queries * stored as Strings that can be searched upon later * Input the list of required features information to convert into the query * Returns the list of queries (Strings) */ private Collection<String> createEnablesQuery() { Collection<String> query = null; Collection<String> requiredFeatures = getRequireFeature(); if (requiredFeatures != null) { query = new ArrayList<String>(); for (String required : requiredFeatures) { String temp = "wlpInformation.provideFeature=" + required; String version = findVersion(); if (version != null) { temp += "&wlpInformation.appliesToFilterInfo.minVersion.value="; temp += version; } temp += "&type="; temp += getType().getValue(); // get the long name of the Type query.add(temp); } } return query; } /** * Uses the filter information to return the first version number * * @return the first version number */ private String findVersion() { WlpInformation wlp = _asset.getWlpInformation(); if (wlp == null) { return null; } Collection<AppliesToFilterInfo> filterInfo = wlp.getAppliesToFilterInfo(); if (filterInfo == null) { return null; } for (AppliesToFilterInfo filter : filterInfo) { if (filter.getMinVersion() != null) { return filter.getMinVersion().getValue(); } } return null; } /* * Calculates the Enabled By query (required by features) */ private Collection<String> createEnabledByQuery() { Collection<String> query = new ArrayList<String>(); String temp = ""; //generate queries temp = "wlpInformation.requireFeature="; temp += getProvideFeature(); String version = findVersion(); if (version != null) { temp += "&wlpInformation.appliesToFilterInfo.minVersion.value="; temp += version; } temp += "&type="; temp += getType().getValue(); query.add(temp); return query; } /** * @return the query for Superseded By or null if this feature * does not declare itself to be superseded by anything. */ private Collection<String> createSupersededByQuery() { Collection<String> supersededBy = _asset.getWlpInformation().getSupersededBy(); Collection<String> query = null; if (supersededBy != null) { //if there are no queries to add query = new ArrayList<String>(); for (String feature : supersededBy) { StringBuilder b = new StringBuilder(); b.append("wlpInformation.shortName="); b.append(feature); b.append("&wlpInformation.appliesToFilterInfo.minVersion.value="); String version = findVersion(); if (version != null) { b.append(version); b.append("&type=com.ibm.websphere.Feature"); } query.add(b.toString()); } } return query; } /** * @return the Supersedes query. Note that this query will always be * set to something because the website can't tell if this features * supersedes anything without running the query. So this method * won't ever return null. */ private Collection<String> createSupersedesQuery() { String shortName = _asset.getWlpInformation().getShortName(); if (shortName != null) { StringBuilder b = new StringBuilder(); b.append("wlpInformation.supersededBy="); b.append(shortName); String version = findVersion(); if (version != null) { b.append("&wlpInformation.appliesToFilterInfo.minVersion.value="); b.append(version); } return Arrays.asList(new String[] { b.toString() }); } else { // if we get here then our shortname is null so we can't create a // query that refers to it. return null; } } /** * This generates the string that should be displayed on the website to indicate * the supported Java versions. The requirements come from the bundle manifests. * The mapping between the two is non-obvious, as it is the intersection between * the Java EE requirement and the versions of Java that Liberty supports. */ private void addVersionDisplayString() { WlpInformation wlp = _asset.getWlpInformation(); JavaSEVersionRequirements reqs = wlp.getJavaSEVersionRequirements(); if (reqs == null) { return; } String minVersion = reqs.getMinVersion(); // Null means no requirements specified which is fine if (minVersion == null) { return; } String requiresJava8 = "Java SE 8"; String requiresJava7or8 = "Java SE 7, Java SE 8"; String requiresJava6or7or8 = "Java SE 6, Java SE 7, Java SE 8"; // The min version should have been validated when the ESA was constructed // so checking for the version string should be safe if (minVersion.equals("1.6.0")) { reqs.setVersionDisplayString(requiresJava6or7or8); return; } if (minVersion.equals("1.7.0")) { reqs.setVersionDisplayString(requiresJava7or8); return; } if (minVersion.equals("1.8.0")) { reqs.setVersionDisplayString(requiresJava8); return; } // The min version string has been generated/validated incorrectly // Can't recover from this, it is a bug in EsaUploader throw new AssertionError(); } /** * @return the query for Superseded By (optional) or null if this feature * does not declare itself to be optionally superseded by anything. */ private Collection<String> createSupersededByOptionalQuery() { Collection<String> supersededByOptional = _asset.getWlpInformation().getSupersededByOptional(); Collection<String> query = null; if (supersededByOptional != null) { //if there are no queries to add query = new ArrayList<String>(); for (String feature : supersededByOptional) { StringBuilder b = new StringBuilder(); b.append("wlpInformation.shortName="); b.append(feature); b.append("&wlpInformation.appliesToFilterInfo.minVersion.value="); String version = findVersion(); if (version != null) { b.append(version); b.append("&type=com.ibm.websphere.Feature"); } query.add(b.toString()); } } return query; } private Link makeLink(String label, String linkLabelProperty, Collection<String> query, String linkLabelPrefix, String linkLabelSuffix) { Link link = makeLink(label, linkLabelProperty, query); link.setLinkLabelPrefix(linkLabelPrefix); link.setLinkLabelSuffix(linkLabelSuffix); return link; } private Link makeLink(String label, String linkLabelProperty, Collection<String> query) { Link link = new Link(); link.setLabel(label); link.setLinkLabelProperty(linkLabelProperty); link.setQuery(query); return link; } /** * Creates the links to enables/enabled-by/supersedes/superseded-by sections. At present, * link labels are hardcoded in this function. We may need to move them in the future if * we need to translate them or if we just don't like the idea of having hardcoded message * strings in here. */ private Collection<Link> createLinks() { ArrayList<Link> links = new ArrayList<Link>(); Collection<String> enablesQuery = createEnablesQuery(); links.add(makeLink("Features that this feature enables", "name", enablesQuery)); Collection<String> enabledByQuery = createEnabledByQuery(); links.add(makeLink("Features that enable this feature", "name", enabledByQuery)); Collection<String> supersedesQuery = createSupersedesQuery(); links.add(makeLink("Features that this feature supersedes", "name", supersedesQuery)); Collection<String> supersededByQuery = createSupersededByQuery(); links.add(makeLink("Features that supersede this feature", "name", supersededByQuery)); // Note: by giving this the same link title as superseded-by, the links appear in the same // link section on the website (but with the suffix that we add here). Collection<String> supersededByOptionalQuery = createSupersededByOptionalQuery(); links.add(makeLink("Features that supersede this feature", "name", supersededByOptionalQuery, null, " (optional)")); return links; } @Override public void updateGeneratedFields(boolean performEditionChecking) throws RepositoryResourceCreationException { super.updateGeneratedFields(performEditionChecking); setLinks(createLinks()); // add the string the website will use for displaying java verison compatibility addVersionDisplayString(); } protected Collection<AppliesToFilterInfo> getAppliesToFilterInfo() { return _asset.getWlpInformation().getAppliesToFilterInfo(); } @Override public RepositoryResourceMatchingData createMatchingData() { ExtendedMatchingData matchingData = new ExtendedMatchingData(); matchingData.setType(getType()); // Regen the appliesToFilterInfo as the level of code that generated each resource may // be different and give us different results so regen it now. List<AppliesToFilterInfo> atfi; try { atfi = generateAppliesToFilterInfoList(false); matchingData.setAtfi(atfi); } catch (RepositoryResourceCreationException e) { // This should only be thrown if validate editions is set to true, for us its set to false } matchingData.setVersion(getVersion()); matchingData.setProvideFeature(getProvideFeature()); return matchingData; } @Override protected Collection<? extends RepositoryResource> getPotentiallyMatchingResources() throws RepositoryBackendException { Collection<RepositoryResource> resources; if (getProvideFeature() != null) { resources = _repoConnection.getMatchingResources(FilterPredicate.areEqual(FilterableAttribute.TYPE, getType()), FilterPredicate.areEqual(FilterableAttribute.SYMBOLIC_NAME, getProvideFeature())); } else { resources = _repoConnection.getMatchingResources(FilterPredicate.areEqual(FilterableAttribute.TYPE, getType())); } return resources; } @Override protected void copyFieldsFrom(RepositoryResourceImpl fromResource, boolean includeAttachmentInfo) { super.copyFieldsFrom(fromResource, includeAttachmentInfo); EsaResourceImpl esaRes = (EsaResourceImpl) fromResource; setAppliesTo(esaRes.getAppliesTo()); setWebDisplayPolicy(esaRes.getWebDisplayPolicy()); setInstallPolicy(esaRes.getInstallPolicy()); setLinks(esaRes.getLinks()); setProvideFeature(esaRes.getProvideFeature()); setProvisionCapability(esaRes.getProvisionCapability()); setRequireFeature(esaRes.getRequireFeature()); setVisibility(esaRes.getVisibility()); setShortName(esaRes.getShortName()); setVanityURL(esaRes.getVanityURL()); } @Override protected String getNameForVanityUrl() { return getProvideFeature(); } /** * Returns the Enables {@link Links} for this feature * * @return */ public void setLinks(Collection<Link> links) { Collection<com.ibm.ws.repository.transport.model.Link> attachmentLinks = new ArrayList<com.ibm.ws.repository.transport.model.Link>(); for (Link link : links) { attachmentLinks.add(link.getLink()); } _asset.getWlpInformation().setLinks(attachmentLinks); } /** * Set the Enables {@link Links} for this feature * * @return */ public Collection<Link> getLinks() { Collection<com.ibm.ws.repository.transport.model.Link> attachmentLinks = _asset.getWlpInformation().getLinks(); Collection<Link> links = new ArrayList<Link>(); for (com.ibm.ws.repository.transport.model.Link link : attachmentLinks) { links.add(new Link(link)); } return links; } /** {@inheritDoc} */ @Override public void addRequireFeature(String requiredFeatureSymbolicName) { _asset.getWlpInformation().addRequireFeature(requiredFeatureSymbolicName); } /** {@inheritDoc} */ @Override public void addRequireFix(String fix) { _asset.getWlpInformation().addRequireFix(fix); } /** {@inheritDoc} */ @Override public Collection<String> getRequireFix() { return _asset.getWlpInformation().getRequireFix(); } /** {@inheritDoc} */ @Override public void setRequireFeature(Collection<String> feats) { _asset.getWlpInformation().setRequireFeature(feats); } /** {@inheritDoc} */ @Override public Collection<String> getRequireFeature() { return _asset.getWlpInformation().getRequireFeature(); } /** {@inheritDoc} */ @Override public void addSupersededBy(String feature) { _asset.getWlpInformation().addSupersededBy(feature); } /** {@inheritDoc} */ @Override public Collection<String> getSupersededBy() { return _asset.getWlpInformation().getSupersededBy(); } /** {@inheritDoc} */ @Override public void addSupersededByOptional(String feature) { _asset.getWlpInformation().addSupersededByOptional(feature); } /** {@inheritDoc} */ @Override public Collection<String> getSupersededByOptional() { return _asset.getWlpInformation().getSupersededByOptional(); } /** * Returns the {@link Visibility} for this feature * * @return */ @Override public Visibility getVisibility() { return _asset.getWlpInformation().getVisibility(); } /** {@inheritDoc} */ @Override public void setVisibility(Visibility vis) { _asset.getWlpInformation().setVisibility(vis); } /** {@inheritDoc} */ @Override public void setShortName(String shortName) { _asset.getWlpInformation().setShortName(shortName); } /** {@inheritDoc} */ @Override public String getShortName() { return _asset.getWlpInformation().getShortName(); } /** {@inheritDoc} */ @Override public String getLowerCaseShortName() { return _asset.getWlpInformation().getLowerCaseShortName(); } /** {@inheritDoc} */ @Override public void setAppliesTo(String appliesTo) { _asset.getWlpInformation().setAppliesTo(appliesTo); } /** {@inheritDoc} */ @Override public String getAppliesTo() { return _asset.getWlpInformation().getAppliesTo(); } // @Override // protected String getVersionForVanityUrl() { // String version = ""; // WlpInformation wlp = _asset.getWlpInformation(); // if (wlp != null) { // Collection<AppliesToFilterInfo> atfis = wlp.getAppliesToFilterInfo(); // if (atfis != null && !atfis.isEmpty()) { // AppliesToFilterInfo atfi = atfis.iterator().next(); // if (atfi != null) { // FilterVersion ver = atfi.getMinVersion(); // if (ver != null) { // version = ver.getLabel(); // } // } // } // } // return version; // } /** {@inheritDoc} */ @Override public void setWebDisplayPolicy(DisplayPolicy policy) { _asset.getWlpInformation().setWebDisplayPolicy(policy); } /** * Get the {@link DisplayPolicy} * * @return {@link DisplayPolicy} in use */ @Override public DisplayPolicy getWebDisplayPolicy() { if (_asset.getWlpInformation() == null) { return null; } return _asset.getWlpInformation().getWebDisplayPolicy(); } /** {@inheritDoc} */ @Override public String getProvisionCapability() { return _asset.getWlpInformation().getProvisionCapability(); } /** {@inheritDoc} */ @Override public void setProvisionCapability(String provisionCapability) { _asset.getWlpInformation().setProvisionCapability(provisionCapability); } /** {@inheritDoc} */ @Override public InstallPolicy getInstallPolicy() { if (_asset.getWlpInformation() == null) { return null; } return _asset.getWlpInformation().getInstallPolicy(); } /** {@inheritDoc} */ @Override public void setInstallPolicy(InstallPolicy policy) { _asset.getWlpInformation().setInstallPolicy(policy); } /** {@inheritDoc} */ @Override public void setJavaSEVersionRequirements(String minimum, String maximum, Collection<String> rawBundleRequirements) { JavaSEVersionRequirements reqs = new JavaSEVersionRequirements(); reqs.setMinVersion(minimum); reqs.setMaxVersion(maximum); reqs.setRawRequirements(rawBundleRequirements); _asset.getWlpInformation().setJavaSEVersionRequirements(reqs); } /** * An ESA may require a minimum or maximum Java version. This is an aggregate min/max, * calculated from the individual requirements of the contained bundles, as specified * by the bundles' Require-Capability header in the bundle manifest. The * <code>JavaSEVersionRequirements</code> contains the set of the Require-Capability * headers, i.e. one from each bundle which specifies the header. * All fields in the version object may be null, if no requirement was specified in the bundles. * * @return */ public JavaSEVersionRequirements getJavaSEVersionRequirements() { return _asset.getWlpInformation().getJavaSEVersionRequirements(); } }