/*******************************************************************************
* Copyright (c) 2007, 2009 Symbian Software Systems 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:
* Andrew Ferguson (Symbian) - Initial implementation
* Anna Dushistova (MontaVista) - bug [247087]
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.export;
import java.io.File;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.ibm.icu.text.MessageFormat;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.IPDOMIndexerTask;
import org.eclipse.cdt.core.dom.IPDOMManager;
import org.eclipse.cdt.core.index.export.ExternalExportProjectProvider;
import org.eclipse.cdt.core.index.export.IExportProjectProvider;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.ProgressProvider;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
/**
* An eclipse application for generating PDOM's without starting the Workbench
*/
public class GeneratePDOMApplication implements IApplication {
private static final String EXPORT_PROJECT_PROVIDER = "ExportProjectProvider"; //$NON-NLS-1$
private static final String DEFAULT_PROJECT_PROVIDER = ExternalExportProjectProvider.class.getName();
public static final String OPT_PROJECTPROVIDER= "-pprovider"; //$NON-NLS-1$
public static final String OPT_TARGET= "-target"; //$NON-NLS-1$
public static final String OPT_QUIET= "-quiet"; //$NON-NLS-1$
public static final String OPT_INDEXER_ID= "-indexer"; //$NON-NLS-1$
/**
* Applications needing to fail in an expected way (without stack dump), should throw
* CoreExceptions with this error code.
*/
public static final int ECODE_EXPECTED_FAILURE= 1;
private static Map<String,IExportProjectProvider> projectInitializers;
/**
* Starts this application
* @throws CoreException on an unexpected failure
*/
public Object start(IApplicationContext context) throws CoreException {
Object result= IApplication.EXIT_OK;
try {
result= startImpl(context);
} catch(CoreException ce) {
IStatus s= ce.getStatus();
if(s.getCode()==ECODE_EXPECTED_FAILURE) {
output(s.getMessage());
} else {
throw ce;
}
}
return result;
}
private Object startImpl(IApplicationContext context) throws CoreException {
String[] appArgs= (String[]) context.getArguments().get(IApplicationContext.APPLICATION_ARGS);
Map<String,List<String>> arguments= CLIUtil.parseToMap(appArgs);
output(Messages.GeneratePDOMApplication_Initializing);
setupCLIProgressProvider();
String pproviderFQN;
if(!arguments.containsKey(OPT_PROJECTPROVIDER)) {
output(MessageFormat.format(Messages.GeneratePDOMApplication_UsingDefaultProjectProvider, new Object[] {DEFAULT_PROJECT_PROVIDER}));
pproviderFQN= DEFAULT_PROJECT_PROVIDER;
} else {
pproviderFQN= CLIUtil.getArg(arguments, OPT_PROJECTPROVIDER, 1).get(0);
}
String target= CLIUtil.getArg(arguments, OPT_TARGET, 1).get(0);
boolean quiet= arguments.get(OPT_QUIET)!=null;
String indexerID= IPDOMManager.ID_FAST_INDEXER;
List<String> indexerIDs= arguments.get(OPT_INDEXER_ID);
if(indexerIDs!=null) {
if(indexerIDs.size()==1) {
indexerID= indexerIDs.get(0);
} else if(indexerIDs.size()>1) {
fail(MessageFormat.format(Messages.GeneratePDOMApplication_InvalidIndexerID, new Object[] {OPT_INDEXER_ID}));
}
}
String[] oldvals= null;
if(!quiet) {
oldvals= new String[] {
System.getProperty(IPDOMIndexerTask.TRACE_ACTIVITY),
System.getProperty(IPDOMIndexerTask.TRACE_PROBLEMS),
System.getProperty(IPDOMIndexerTask.TRACE_STATISTICS),
};
System.setProperty(IPDOMIndexerTask.TRACE_ACTIVITY, Boolean.TRUE.toString());
System.setProperty(IPDOMIndexerTask.TRACE_PROBLEMS, Boolean.TRUE.toString());
System.setProperty(IPDOMIndexerTask.TRACE_STATISTICS, Boolean.TRUE.toString());
}
try {
IExportProjectProvider pprovider = getExportProjectProvider(pproviderFQN);
if(pprovider==null) {
fail(MessageFormat.format(Messages.GeneratePDOMApplication_CouldNotFindInitializer, new Object[]{pproviderFQN}));
}
File targetLocation = new File(target);
GeneratePDOM generate = new GeneratePDOM(pprovider, appArgs, targetLocation, indexerID);
output(Messages.GeneratePDOMApplication_GenerationStarts);
IStatus status = generate.run(); // CoreException handled in start method
if(!status.isOK()){
output(status.getMessage());
}
output(Messages.GeneratePDOMApplication_GenerationEnds);
} finally {
if (oldvals != null) {
restoreSystemProperty(IPDOMIndexerTask.TRACE_ACTIVITY, oldvals[0]);
restoreSystemProperty(IPDOMIndexerTask.TRACE_PROBLEMS, oldvals[1]);
restoreSystemProperty(IPDOMIndexerTask.TRACE_STATISTICS, oldvals[2]);
}
}
return null;
}
private void restoreSystemProperty(String key, String value) {
if (value == null) {
System.clearProperty(key);
} else {
System.setProperty(key, value);
}
}
protected void output(String s) {
System.out.println(s);
}
public void stop() {
// do nothing
}
/**
* Causes the application to fail in a way that has been anticipated (e.g. a command-line or interface
* contract violation by a extension implementation)
* @param message
* @throws CoreException
*/
public static final void fail(String message) throws CoreException {
IStatus status= new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, ECODE_EXPECTED_FAILURE, message, null);
CCorePlugin.log(status);
throw new CoreException(status);
}
/**
* Returns the IExportProjectProvider registered in the plug-in registry under the
* specified fully qualified class name
* May return null
* @param fqn
* @return
*/
private static synchronized IExportProjectProvider getExportProjectProvider(String fqn) {
if(projectInitializers==null) {
projectInitializers = new HashMap<String, IExportProjectProvider>();
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint indexExtensions = registry.getExtensionPoint(CCorePlugin.INDEX_UNIQ_ID);
IExtension[] extensions = indexExtensions.getExtensions();
for (IExtension extension : extensions) {
IConfigurationElement[] ce = extension.getConfigurationElements();
for (IConfigurationElement element : ce) {
if(element.getName().equals(EXPORT_PROJECT_PROVIDER)) {
try {
IExportProjectProvider epp = (IExportProjectProvider) element.createExecutableExtension("class"); //$NON-NLS-1$
projectInitializers.put(epp.getClass().getName(), epp);
} catch(CoreException cee) {
CCorePlugin.log(cee);
}
}
}
}
}
IExportProjectProvider initer = projectInitializers.get(fqn);
return initer;
}
/**
* In this application, the usual progress reports are redirected to standard out
*/
private void setupCLIProgressProvider() {
ProgressProvider pp = new ProgressProvider() {
class IndexingStreamProgressMonitor extends StreamProgressMonitor {
public IndexingStreamProgressMonitor(PrintStream writer) {
super(writer);
}
@Override
protected boolean shouldOutput() {
return taskName!=null && taskName.equals(CCorePlugin.getResourceString("pdom.indexer.task")); //$NON-NLS-1$
}
}
@Override
public IProgressMonitor createMonitor(Job job) {
return new IndexingStreamProgressMonitor(System.out);
}
@Override
public IProgressMonitor createMonitor(Job job,
IProgressMonitor group, int ticks) {
return new NullProgressMonitor();
}
@Override
public IProgressMonitor createProgressGroup() {
return new NullProgressMonitor();
}
};
Job.getJobManager().setProgressProvider(pp);
}
static class StreamProgressMonitor implements IProgressMonitor {
volatile boolean canceled;
volatile int totalWork;
volatile double worked;
final PrintStream writer;
volatile String taskName, subTask;
Object mutex = new Object();
StreamProgressMonitor(PrintStream writer) {
this.writer = writer;
this.totalWork = -1;
}
protected boolean shouldOutput() {
return true;
}
public void done() {
}
public void worked(int work) {
internalWorked(work);
}
public void beginTask(String name, int total) {
this.taskName = name;
this.totalWork = total;
}
public void internalWorked(double work) {
synchronized(mutex) {
worked += work;
int pc = totalWork<1 ? 0 : (int) ((worked*100D)/totalWork);
if(shouldOutput()) {
writer.println(pc+"% "+subTask); //$NON-NLS-1$
}
}
}
public boolean isCanceled() {
return canceled;
}
public void setCanceled(boolean value) {
canceled = value;
}
public void setTaskName(String name) {
taskName = name;
}
public void subTask(String name) {
subTask = name;
}
}
}