/*************************************************************************************
* Copyright (c) 2013 Red Hat, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* JBoss by Red Hat - Initial implementation.
************************************************************************************/
package org.jboss.tools.stacks.core.model;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Properties;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.jboss.jdf.stacks.client.DefaultStacksClientConfiguration;
import org.jboss.jdf.stacks.client.StacksClient;
import org.jboss.jdf.stacks.client.StacksClientConfiguration;
import org.jboss.jdf.stacks.client.messages.StacksMessages;
import org.jboss.jdf.stacks.model.Stacks;
import org.jboss.jdf.stacks.parser.Parser;
import org.jboss.tools.foundation.core.ecf.URLTransportUtility;
import org.jboss.tools.foundation.core.jobs.BarrierProgressWaitJob;
import org.jboss.tools.foundation.core.jobs.BarrierProgressWaitJob.IRunnableWithProgress;
import org.jboss.tools.stacks.core.StacksCoreActivator;
import org.jboss.tools.stacks.core.Trace;
/**
* A StacksManager is in charge of retrieving a file from a URL or standard location
* and returning a jdf.stacks model object generated via the stacks client.
*/
public class StacksManager {
/**
* @deprecated
*/
private static final String STACKS_URL_PROPERTY = "org.jboss.examples.stacks.url";
private static final String URL_PROPERTY_STACKS = "org.jboss.tools.stacks.url_stacks";
private static final String URL_PROPERTY_PRESTACKS = "org.jboss.tools.stacks.url_prestacks";
private static final String STACKS_URL;
private static final String PRESTACKS_URL;
// Declare the types of stacks available for fetch
public enum StacksType {
STACKS_TYPE, PRESTACKS_TYPE
}
// Load the default stacks url and prestacks url from a sysprop or jar
static {
STACKS_URL = System.getProperty(URL_PROPERTY_STACKS, System.getProperty(STACKS_URL_PROPERTY, System.getProperty(StacksClientConfiguration.REPO_PROPERTY, getStacksDefaultUrlFromJar())));
PRESTACKS_URL = System.getProperty(URL_PROPERTY_PRESTACKS, System.getProperty("jdf.prestacks.client.repo", getPreStacksDefaultUrlFromJar()));
}
/**
* Fetch the default stacks model.
*
* @param monitor
* @return
*/
public Stacks getStacks(IProgressMonitor monitor) {
Stacks[] all = getStacks("Fetching JBoss Stacks", monitor, StacksType.STACKS_TYPE);
if( all != null && all.length > 0)
return all[0];
return null;
}
/**
* Fetch an array of stacks models where each element represents one of the StacksType urls
*
* @param jobName
* @param monitor
* @param types
* @return
*/
public Stacks[] getStacks(String jobName, IProgressMonitor monitor, StacksType... types) {
if( types == null )
return new Stacks[0];
Trace.trace(Trace.STRING_FINEST, "Request received for " + types.length + " stacks types.");
ArrayList<Stacks> ret = new ArrayList<Stacks>(types.length);
monitor.beginTask(jobName, types.length * 100);
for( int i = 0; i < types.length; i++ ) {
switch(types[i] ) {
case STACKS_TYPE:
Trace.trace(Trace.STRING_FINEST, "Loading Stacks Model from " + STACKS_URL);
Stacks s = getStacks(STACKS_URL, jobName, new SubProgressMonitor(monitor, 50));
if( s == null && !monitor.isCanceled()) {
StacksCoreActivator.pluginLog().logWarning("Stacks from "+ STACKS_URL +" can not be read, using client mechanism instead");
s = getDefaultStacksFromClient(new SubProgressMonitor(monitor, 50));
}
if( s != null )
ret.add(s);
break;
case PRESTACKS_TYPE:
// Pre-stacks has no fall-back mechanism at this time
Trace.trace(Trace.STRING_FINEST, "Loading Stacks Model from " + PRESTACKS_URL);
Stacks s2 = getStacks(PRESTACKS_URL, jobName, new SubProgressMonitor(monitor, 100));
if( s2 != null )
ret.add(s2);
break;
default:
break;
}
}
monitor.done();
return (Stacks[]) ret.toArray(new Stacks[ret.size()]);
}
/**
* Fetch the stacks model representing a given arbitrary url.
* The remote file will be cached only until the system exits.
*
* @param url
* @param monitor
* @return
*/
public Stacks getStacks(String url, IProgressMonitor monitor) {
return getStacks(url, url, URLTransportUtility.CACHE_UNTIL_EXIT, monitor);
}
/**
* Fetch the stacks model for a given url. Cache the remote file
* with a duration representing forever, or, until the remote file is newer.
*
* @param url The url
* @param jobName Job name for display purposes
* @param monitor
* @return
*/
protected Stacks getStacks(String url, String jobName, IProgressMonitor monitor) {
return getStacks(url, jobName, URLTransportUtility.CACHE_FOREVER, monitor);
}
/**
* Fetch the stacks model for the given url.
*
* @param url
* @param jobName
* @param cacheType
* @param monitor
* @return
*/
protected Stacks getStacks(String url, String jobName, int cacheType, IProgressMonitor monitor) {
return getStacksFromURL(url, jobName, cacheType, monitor);
}
protected Stacks getStacksFromURL(String url, String jobName, int cacheType, IProgressMonitor monitor) {
Stacks stacks = null;
try {
Trace.trace(Trace.STRING_FINEST, "Locating or downloading file for " + url);
File f = getCachedFileForURL(url, jobName, cacheType, monitor);
return getStacksFromFile(f);
} catch (Exception e) {
StacksCoreActivator.pluginLog().logError("Can't access or parse " + url, e ); //$NON-NLS-1$
}
return stacks;
}
protected Stacks getStacksFromFile(File f) throws IOException {
if (f != null && f.exists()) {
Trace.trace(Trace.STRING_FINEST, "Local file for url exists");
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
Parser p = new Parser();
return p.parse(fis);
} finally {
close(fis);
}
}
return null;
}
private Stacks getDefaultStacksFromClient(IProgressMonitor monitor) {
if (!monitor.isCanceled()) {
final StacksClient client = new StacksClient(new DefaultStacksClientConfiguration(), new JBTStacksMessages());
IRunnableWithProgress barrierRunnable = new IRunnableWithProgress() {
public Object run(IProgressMonitor monitor) throws Exception {
StacksCoreActivator.pluginLog().logWarning("BarrierProgressWaitJob - loading Stacks Client values");
return client.getStacks();
}
};
BarrierProgressWaitJob fromClientJob = new BarrierProgressWaitJob("Load stacks using stacks client", barrierRunnable);
fromClientJob.schedule();
fromClientJob.monitorSafeJoin(monitor);
Throwable t = fromClientJob.getThrowable();
Object ret = fromClientJob.getReturnValue();
if( t != null ) {
StacksCoreActivator.pluginLog().logError(t);
}
return (Stacks)ret;
}
return null;
}
/**
* Fetch a local cache of the remote file.
* If the remote file is newer than the local, update it.
*
* @param url
* @param jobName
* @param monitor
* @return
*/
protected File getCachedFileForURL(String url, String jobName, IProgressMonitor monitor) throws CoreException {
return getCachedFileForURL(url, jobName, URLTransportUtility.CACHE_FOREVER, monitor);
}
/**
* Fetch a local cache of the remote file.
* If the remote file is newer than the local, update it.
*
* @param url A url to fetch the stacks model from
* @param jobName A job name passed into the downloader for display purposes
* @param cacheType An integer representing the duration to cache the downloaded file
* @param monitor A file representign the model
* @return
*/
protected File getCachedFileForURL(String url, String jobName, int cacheType, IProgressMonitor monitor) throws CoreException {
return new URLTransportUtility().getCachedFileForURL(url, jobName, cacheType, monitor);
}
/*
* Read the stacks.yaml location from inside our client jar
*/
private static String getStacksDefaultUrlFromJar() {
return getUrlFromJar(StacksClientConfiguration.REPO_PROPERTY);
}
private static String getPreStacksDefaultUrlFromJar() {
return getUrlFromJar(StacksClientConfiguration.PRESTACKS_REPO_PROPERTY);
}
private static String getUrlFromJar(String prop) {
InputStream is = null;
try {
is = StacksManager.class.getResourceAsStream("/org/jboss/jdf/stacks/client/config.properties"); //$NON-NLS-1$
Properties p = new Properties();
p.load(is);
return p.getProperty(prop);
} catch (Exception e) {
StacksCoreActivator.pluginLog().logWarning("Can't read stacks url from the stacks-client.jar", e); //$NON-NLS-1$
} finally {
close(is);
}
return null;
}
private static class JBTStacksMessages implements StacksMessages {
public void showDebugMessage(String arg0) {
Trace.trace(Trace.STRING_FINER, arg0);
}
public void showInfoMessage(String arg0) {
Trace.trace(Trace.STRING_INFO, arg0);
}
public void showErrorMessage(String arg0) {
StacksCoreActivator.pluginLog().logError(arg0);
}
public void showErrorMessageWithCause(String arg0, Throwable t) {
StacksCoreActivator.pluginLog().logError(arg0, t);
}
public void showWarnMessage(String arg0) {
StacksCoreActivator.pluginLog().logWarning(arg0);
}
}
/*
* Close an inputstream
*/
private static void close(InputStream is) {
if( is != null ) {
try {
is.close();
} catch(IOException ie) {
// IGNORE
}
}
}
}