/*
* #%L
* carewebframework
* %%
* Copyright (C) 2008 - 2016 Regenstrief Institute, Inc.
* %%
* 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.
*
* This Source Code Form is also subject to the terms of the Health-Related
* Additional Disclaimer of Warranty and Limitation of Liability available at
*
* http://www.carewebframework.org/licensing/disclaimer.
*
* #L%
*/
package org.carewebframework.api;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.jar.Manifest;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.carewebframework.api.spring.SpringUtil;
import org.carewebframework.common.StrUtil;
import org.springframework.core.io.Resource;
/**
* Service that provides access to manifests for all components on the class path.
*/
public class ManifestIterator implements Iterable<Manifest> {
private static class ManifestEx extends Manifest {
private final String path;
private ManifestEx(Resource resource) throws IOException {
super(resource.getInputStream());
path = StringUtils.removeEnd(resource.getURL().getPath(), MANIFEST_PATH);
processFiles(resource, LICENSE_FILES, "License");
processFiles(resource, README_FILES, "Description");
}
private void processFiles(Resource resource, String[] files, String attributeName) throws IOException {
for (String file : files) {
Resource res = resource.createRelative(file);
if (res.exists()) {
String text = new String(IOUtils.toCharArray(res.getInputStream(), StrUtil.CHARSET));
getMainAttributes().putValue(attributeName, text);
break;
}
}
}
}
private static final ManifestIterator instance = new ManifestIterator();
private static final Log log = LogFactory.getLog(ManifestIterator.class);
protected static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
private static final String[] LICENSE_FILES = { "LICENSE.TXT", "license.txt", "LICENSE", "license" };
private static final String[] README_FILES = { "README.TXT", "readme.txt", "README", "readme" };
private Manifest primaryManifest;
private List<Manifest> manifests;
/**
* Returns the manifest iterator instance.
*
* @return The manifest iterator.
*/
public static ManifestIterator getInstance() {
return instance;
}
/**
* Enforce singleton instance.
*/
private ManifestIterator() {
super();
}
/**
* Initialize the manifest list if not already done. This is done by iterating over the class
* path to locate all manifest files.
*/
public void init() {
if (manifests == null) {
manifests = new ArrayList<>();
try {
primaryManifest = addToList(SpringUtil.getResource(MANIFEST_PATH));
Resource[] resources = SpringUtil.getResources("classpath*:/" + MANIFEST_PATH);
for (Resource resource : resources) {
addToList(resource);
}
} catch (Exception e) {
log.error("Error enumerating manifests.", e);
}
}
}
/**
* Returns a manifest based on the input path.
*
* @param path The path whose associated manifest is sought.
* @return The manifest found on the specified path, or null if none.
*/
public Manifest findByPath(String path) {
for (Manifest manifest : this) {
String mpath = ((ManifestEx) manifest).path;
if (path.startsWith(mpath)) {
return manifest;
}
}
return null;
}
/**
* Returns the iterator for all registered manifests.
*
* @return The manifest iterator.
*/
@Override
public Iterator<Manifest> iterator() {
init();
return manifests.iterator();
}
/**
* Returns the primary manifest for the application, if any.
*
* @return The primary manifest, or null if not found.
*/
public Manifest getPrimaryManifest() {
init();
return primaryManifest;
}
/**
* Adds the manifest referenced by the specified resource to the list.
*
* @param resource Resource that references a manifest file.
* @return The manifest that was added, or null if not found or an error occurred.
*/
private Manifest addToList(Resource resource) {
try {
if (resource != null && resource.exists()) {
Manifest manifest = new ManifestEx(resource);
manifests.add(manifest);
return manifest;
}
} catch (Exception e) {
log.debug("Exception occurred reading manifest: " + resource);
}
return null;
}
}