org.apache.openejb.loader.ProvisioningUtil Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.openejb.loader;
import org.w3c.dom.Document;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
public final class ProvisioningUtil {
private static final SAXParserFactory FACTORY = SAXParserFactory.newInstance();
static {
FACTORY.setNamespaceAware(false);
FACTORY.setValidating(false);
}
public static final String OPENEJB_DEPLOYER_CACHE_FOLDER = "openejb.deployer.cache.folder";
public static final String HTTP_PREFIX = "http";
public static final String HTTPS_PREFIX = "https";
public static final String MVN_PREFIX = "mvn:";
public static final String SNAPSHOT_SUFFIX = "-SNAPSHOT";
private static final int CONNECT_TIMEOUT = 10000;
private static final String ADDITIONAL_LIB_CONFIG = "provisioning.properties";
private static final String REPO1 = "http://repo1.maven.org/maven2/";
private static final String APACHE_SNAPSHOT = "https://repository.apache.org/snapshots/";
private static final String ZIP_KEY = "zip";
private static final String DESTINATION_KEY = "destination";
private static final String JAR_KEY = "jar";
public static final String TEMP_DIR = "temp";
private ProvisioningUtil() {
// no-op
}
public static String cache() {
return System.getProperty(OPENEJB_DEPLOYER_CACHE_FOLDER, TEMP_DIR);
}
public static File cacheFile(final String path) {
final File cacheDir = new File(SystemInstance.get().getBase().getDirectory(), cache());
if (!cacheDir.exists() && !cacheDir.mkdirs()) {
throw new RuntimeException("Failed to create the directory: " + cacheDir);
}
return new File(cacheDir, path);
}
public static String copyTryingProxies(final URI source, final File destination) throws Exception {
final InputStream is = inputStreamTryingProxies(source);
if (is == null) {
return null;
}
try {
IO.copy(is, destination);
} finally {
IO.close(is);
}
return destination.getAbsolutePath();
}
public static InputStream inputStreamTryingProxies(final URI source) throws Exception {
final URL url = source.toURL();
for (final Proxy proxy : ProxySelector.getDefault().select(source)) {
// try to connect
try {
final URLConnection urlConnection = url.openConnection(proxy);
urlConnection.setConnectTimeout(CONNECT_TIMEOUT);
return new BufferedInputStream(urlConnection.getInputStream());
} catch (final IOException e) {
// ignored
}
}
return null;
}
public static String lastPart(final String location) {
final int idx = location.lastIndexOf('/');
if (idx <= 0) {
return location;
}
return location.substring(idx + 1, location.length());
}
/**
*
* @param rawLocation
* @return
*/
public static String realLocation(final String rawLocation) {
if (hasHttpOrHttpsPrefix(rawLocation)) {
final File file = cacheFile(lastPart(rawLocation));
if (file.exists()) {
return file.getAbsolutePath();
}
String path = null;
try {
path = copyTryingProxies(new URI(rawLocation), file);
} catch (final Exception e1) {
// ignored
}
if (path != null) {
return path;
}
}
try { // full maven resolution
final Class> clazz = ProvisioningUtil.class.getClassLoader().loadClass("org.apache.openejb.resolver.Resolver");
final LocationResolver instance = (LocationResolver) clazz.newInstance();
return instance.resolve(rawLocation);
} catch (final Throwable e) { // NoClassDefFoundError is not an exception
return fallback(rawLocation);
}
}
private static String fallback(final String rawLocation) {
if (rawLocation.startsWith(MVN_PREFIX)) {
try {
final String repo1Url = quickMvnUrl(rawLocation.substring(MVN_PREFIX.length()).replace(":", "/"));
final String real = realLocation(repo1Url);
return real;
} catch (final MalformedURLException e1) {
Logger.getLogger(ProvisioningUtil.class.getName()).severe("Can't find " + rawLocation);
}
} else { // try url
try {
final File file = cacheFile(lastPart(rawLocation));
final URL url = new URL(rawLocation);
InputStream is = null;
try {
is = new BufferedInputStream(url.openStream());
IO.copy(is, file);
return file.getAbsolutePath();
} finally {
IO.close(is);
}
} catch (final Exception e1) {
// no-op
}
}
// if it was not an url that's just a file path
return rawLocation;
}
public static String quickMvnUrl(final String raw) throws MalformedURLException {
final String base;
if (raw.contains(SNAPSHOT_SUFFIX) && raw.contains("apache")) {
base = APACHE_SNAPSHOT;
} else {
base = REPO1;
}
StringBuilder builder = new StringBuilder();
final String toParse;
if (!raw.contains("!")) {
// try first local file with default maven settings
final File file = new File(m2Home() + mvnArtifactPath(raw, null));
if (file.exists()) {
return file.getAbsolutePath();
}
// else use repo1
builder = new StringBuilder();
builder.append(base);
toParse = raw;
// try first locally
} else {
final int repoIdx = raw.lastIndexOf("!");
toParse = raw.substring(repoIdx + 1);
final String repo = raw.substring(0, repoIdx);
builder.append(repo);
if (!repo.endsWith("/")) {
builder.append("/");
}
}
builder.append(mvnArtifactPath(toParse, base));
return builder.toString();
}
private static String m2Home() {
String home = "";
File f = new File(SystemInstance.get().getProperty("openejb.m2.home", System.getProperty("user.home") + "/.m2/repository/"));
if (f.exists()) {
home = f.getAbsolutePath();
} else {
f = new File(SystemInstance.get().getProperty("openejb.m2.home", System.getProperty("user.home") + "/.m2/settings.xml"));
if (f.exists()) {
try {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
final Document document = builder.parse(f);
final XPathFactory xpf = XPathFactory.newInstance();
final XPath xp = xpf.newXPath();
home = xp.evaluate("//settings/localRepository/text()", document.getDocumentElement());
} catch (final Exception ignore) {
//no-op
}
}
}
return (home.endsWith("/") ? home : home + "/");
}
private static String mvnArtifactPath(final String toParse, final String snapshotBase) throws MalformedURLException {
final StringBuilder builder = new StringBuilder();
final String[] segments = toParse.split("/");
if (segments.length < 3) {
throw new MalformedURLException("Invalid path. " + toParse);
}
final String group = segments[0];
if (group.trim().isEmpty()) {
throw new MalformedURLException("Invalid groupId. " + toParse);
}
builder.append(group.replace('.', '/')).append("/");
final String artifact = segments[1];
if (artifact.trim().isEmpty()) {
throw new MalformedURLException("Invalid artifactId. " + toParse);
}
builder.append(artifact).append("/");
final String version = segments[2];
if (version.trim().isEmpty()) {
throw new MalformedURLException("Invalid version. " + toParse);
}
builder.append(version).append("/");
String artifactVersion;
if (snapshotBase != null && hasHttpOrHttpsPrefix(snapshotBase) && version.endsWith(SNAPSHOT_SUFFIX)) {
final String meta = snapshotBase + builder.toString() + "maven-metadata.xml";
final URL url = new URL(meta);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream is = null;
try {
is = inputStreamTryingProxies(url.toURI());
IO.copy(is, out);
artifactVersion = extractLastSnapshotVersion(version, new ByteArrayInputStream(out.toByteArray()));
} catch (final Exception e) {
artifactVersion = version;
} finally {
IO.close(is);
}
} else {
artifactVersion = version;
}
String type = "jar";
if (segments.length >= 4 && segments[3].trim().length() > 0) {
type = segments[3];
}
String fullClassifier = null;
if (segments.length >= 5 && segments[4].trim().length() > 0) {
fullClassifier = "-" + segments[4];
}
builder.append(artifact).append("-").append(artifactVersion);
if (fullClassifier != null) {
builder.append(fullClassifier);
}
return builder.append(".").append(type).toString();
}
private static boolean hasHttpOrHttpsPrefix(final String str) {
return str.startsWith(HTTP_PREFIX) || str.startsWith(HTTPS_PREFIX);
}
private static String extractLastSnapshotVersion(final String defaultVersion, final InputStream metadata) {
final QuickMvnMetadataParser handler = new QuickMvnMetadataParser();
try {
final SAXParser parser = FACTORY.newSAXParser();
parser.parse(metadata, handler);
if (handler.timestamp != null && handler.buildNumber != null) {
return defaultVersion.substring(0, defaultVersion.length() - SNAPSHOT_SUFFIX.length()) + "-" + handler.timestamp.toString() + "-" + handler.buildNumber.toString();
}
} catch (final Exception e) {
// no-op: not parseable so ignoring
}
return defaultVersion;
}
public static Collection addAdditionalLibraries() throws IOException {
final File conf = SystemInstance.get().getConf(ADDITIONAL_LIB_CONFIG);
if (conf == null || !conf.exists()) {
return Collections.emptyList();
}
final Properties additionalLibProperties = IO.readProperties(conf);
final List libToCopy = new ArrayList();
final String toCopy = additionalLibProperties.getProperty(JAR_KEY);
if (toCopy != null) {
for (final String lib : toCopy.split(",")) {
libToCopy.add(realLocation(lib.trim()));
}
}
final String toExtract = additionalLibProperties.getProperty(ZIP_KEY);
if (toExtract != null) {
for (final String zip : toExtract.split(",")) {
libToCopy.addAll(extract(realLocation(zip)));
}
}
final File destination;
if (additionalLibProperties.containsKey(DESTINATION_KEY)) {
destination = new File(additionalLibProperties.getProperty(DESTINATION_KEY));
} else {
destination = new File(SystemInstance.get().getBase().getDirectory(), Embedder.ADDITIONAL_LIB_FOLDER);
}
if (!destination.exists()) {
Files.mkdirs(destination);
}
final Collection newFiles = new ArrayList(libToCopy.size());
for (final String lib : libToCopy) {
newFiles.add(copy(new File(lib), destination));
}
return newFiles;
}
private static File copy(final File file, final File lib) throws IOException {
final File dest = new File(lib, file.getName());
if (dest.exists()) {
return dest;
}
IO.copy(file, dest);
return dest;
}
private static Collection extract(final String zip) throws IOException {
final File tmp = new File(SystemInstance.get().getBase().getDirectory(), TEMP_DIR);
if (!tmp.exists()) {
try {
Files.mkdirs(tmp);
} catch (final Files.FileRuntimeException fre) {
// ignored
}
}
final File zipFile = new File(realLocation(zip));
final File extracted = new File(tmp, zipFile.getName().replace(".zip", ""));
if (extracted.exists()) {
return list(extracted);
} else {
Files.mkdirs(extracted);
}
Zips.unzip(zipFile, extracted);
return list(extracted);
}
private static Collection list(final File dir) {
if (dir == null) {
return Collections.emptyList();
}
final Collection libs = new ArrayList();
final File[] files = dir.listFiles();
if (files == null) {
return Collections.emptyList();
}
for (final File file : files) {
if (file.isDirectory()) {
libs.addAll(list(file));
} else {
libs.add(file.getAbsolutePath());
}
}
return libs;
}
private static class QuickMvnMetadataParser extends DefaultHandler {
private boolean readTs;
private boolean readBn;
private StringBuilder timestamp;
private StringBuilder buildNumber;
@Override
public void startElement(final String uri, final String localName,
final String qName, final Attributes attributes) throws SAXException {
if ("timestamp".equalsIgnoreCase(qName)) {
readTs = true;
timestamp = new StringBuilder();
} else if ("buildNumber".equalsIgnoreCase(qName)) {
readBn = true;
buildNumber = new StringBuilder();
}
}
@Override
public void characters(final char[] ch, final int start, final int length) throws SAXException {
if (readBn && buildNumber != null) {
buildNumber.append(new String(ch, start, length));
} else if (readTs && timestamp != null) {
timestamp.append(new String(ch, start, length));
}
}
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
if ("timestamp".equalsIgnoreCase(qName)) {
readTs = false;
} else if ("buildNumber".equalsIgnoreCase(qName)) {
readBn = false;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy