/*******************************************************************************
* 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.internal;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import org.apache.aries.util.manifest.ManifestHeaderProcessor;
import org.apache.aries.util.manifest.ManifestHeaderProcessor.NameValuePair;
import org.apache.aries.util.manifest.ManifestProcessor;
import org.osgi.framework.Version;
import com.ibm.ws.repository.common.enums.Visibility;
public class EsaManifest {
private static final Set<String> LOCALIZABLE_HEADERS = new HashSet<String>(Arrays.asList("Subsystem-Name", "Subsystem-Description"));
/**
* Create a new instance of this class for the supplied ESA file.
*
* @param esa The ESA to load
* @return The {@link EsaManifest} for working with the properties of the ESA
* @throws ZipException
* @throws IOException
*/
public static EsaManifest constructInstance(File esa)
throws ZipException, IOException {
// Find the manifest - case isn't guaranteed so do a search
ZipFile zip = new ZipFile(esa);
Enumeration<? extends ZipEntry> zipEntries = zip.entries();
ZipEntry subsystemEntry = null;
while (zipEntries.hasMoreElements()) {
ZipEntry nextEntry = zipEntries.nextElement();
if ("OSGI-INF/SUBSYSTEM.MF".equalsIgnoreCase(nextEntry.getName())) {
subsystemEntry = nextEntry;
}
}
return new EsaManifest(
zip.getInputStream(subsystemEntry), zip);
}
private final ZipFile esa;
private final Manifest mf;
private String symbolicName;
private Map<String, String> symbolicNameAttrs;
private EsaManifest(InputStream manifestInputStream,
ZipFile esa) throws IOException {
mf = ManifestProcessor.parseManifest(manifestInputStream);
this.esa = esa;
}
public String getHeader(String header) {
return mf.getMainAttributes().getValue(header);
}
public String getHeader(String header, Locale locale) {
String headerValue = mf.getMainAttributes().getValue(header);
if (LOCALIZABLE_HEADERS.contains(header) && headerValue != null && headerValue.startsWith("%")) {
Properties props = getLocaleTranslations(locale);
if (props != null) {
headerValue = props.getProperty(headerValue.substring(1), headerValue);
}
}
return headerValue;
}
private Properties getLocaleTranslations(Locale locale) {
// Look at where to searh for localization files
String localizationLocation = this.getHeader("Subsystem-Localization");
if (localizationLocation == null) {
return null;
}
ZipEntry[] entries = new ZipEntry[] {
this.esa.getEntry(localizationLocation + "_"
+ locale.toString() + ".properties"),
this.esa.getEntry(localizationLocation + "_"
+ locale.getLanguage() + ".properties"),
this.esa.getEntry(localizationLocation + ".properties") };
for (ZipEntry entry : entries) {
if (entry != null) {
InputStreamReader inputStreamReader = null;
try {
Properties props = new Properties();
inputStreamReader = new InputStreamReader(this.esa.getInputStream(entry));
props.load(inputStreamReader);
return props;
} catch (IOException e) {
} finally {
if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (IOException e) {
}
}
}
}
}
return null;
}
public String getIbmShortName() {
return getHeader("IBM-ShortName");
}
private void parseSymbolicName() {
if (symbolicName != null) {
return;
}
NameValuePair nvp = org.apache.aries.util.manifest.ManifestHeaderProcessor.parseBundleSymbolicName(getHeader("Subsystem-SymbolicName"));
symbolicName = nvp.getName();
symbolicNameAttrs = nvp.getAttributes();
if (symbolicNameAttrs == null) {
// Don't leave symbolicNameAttrs as null because it would necessitate
// checks in a few other places
symbolicNameAttrs = Collections.emptyMap();
}
}
/**
* @return
*/
public String getSymbolicName() {
parseSymbolicName();
return symbolicName;
}
/**
* @return
*/
public Version getVersion() {
String versionString = getHeader("Subsystem-Version");
Version version;
if (versionString == null) {
version = Version.emptyVersion;
} else {
version = new Version(versionString);
}
return version;
}
/**
* @return
*/
public boolean isAutoFeature() {
return getHeader("IBM-Provision-Capability") != null;
}
/**
* @return
*/
public String getSupersededBy() {
parseSymbolicName();
boolean isSuperseded = Boolean.parseBoolean(symbolicNameAttrs.get("superseded"));
String supersededBy = symbolicNameAttrs.get("superseded-by");
if (!isSuperseded && supersededBy == null) {
return null;
} else if (isSuperseded && supersededBy != null) {
return supersededBy;
} else {
// TODO: throw exception
throw new RuntimeException("Superseded and superseded-by not set correctly");
}
}
/**
* @return
*/
public Visibility getVisibility() {
parseSymbolicName();
String visibilityString = symbolicNameAttrs.get("visibility:");
Visibility visibility = Visibility.PRIVATE;
if (visibilityString != null) {
switch (visibilityString) {
case "public":
visibility = Visibility.PUBLIC;
break;
case "protected":
visibility = Visibility.PROTECTED;
break;
case "private":
visibility = Visibility.PRIVATE;
break;
case "install":
visibility = Visibility.INSTALL;
break;
default:
visibility = Visibility.PRIVATE;
}
}
return visibility;
}
public List<String> getRequiredFeatures() {
List<String> result = new ArrayList<String>();
Map<String, Map<String, String>> featureContentMap = ManifestHeaderProcessor.parseImportString(getHeader("Subsystem-Content"));
for (Entry<String, Map<String, String>> contentEntry : featureContentMap.entrySet()) {
String symbolicName = contentEntry.getKey();
Map<String, String> attributes = contentEntry.getValue();
if ("osgi.subsystem.feature".equals(attributes.get("type"))) {
result.add(symbolicName);
}
}
return result;
}
}