/*******************************************************************************
* Copyright © 2011, 2013 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.javart.ide;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import org.eclipse.edt.javart.messages.Message;
import org.eclipse.edt.javart.resources.egldd.RuntimeDeploymentDesc;
import resources.edt.binding.BindingResourceProcessor;
import resources.edt.binding.RuntimeResourceLocator;
import eglx.lang.AnyException;
/**
* Implements SysLib.ResourceLocator to handle locating deployment descriptors for a Java test environment, as well as
* supporting special binding URIs such as "workspace://".
*/
public class IDEResourceLocator extends RuntimeResourceLocator {
/**
* Maps DD names to absolute filesystem paths.
*/
private Map<String,String> ddPaths = new HashMap<String, String>();
/**
* An alternate (static) method that parses the DD file. If unspecified then {@link RuntimeDeploymentDesc#createDeploymentDescriptor(String, InputStream)}
* will be used. It MUST have the same signature as {@link RuntimeDeploymentDesc#createDeploymentDescriptor(String, InputStream)}.
*/
private Method ddParserMethod;
/**
* Constructor.
*
* @param idePort The port on which the IDE can be reached.
*/
public IDEResourceLocator() {
}
/**
* Sets the alternate (static) method that parses the DD file. If unspecified then {@link RuntimeDeploymentDesc#createDeploymentDescriptor(String, InputStream)}
* will be used. It MUST have the same signature as {@link RuntimeDeploymentDesc#createDeploymentDescriptor(String, InputStream)}.
*/
public void setDDParser(Method method) {
this.ddParserMethod = method;
}
@Override
public RuntimeDeploymentDesc getDeploymentDesc(URI propertyFileUri) {
RuntimeDeploymentDesc dd = getDeploymentDesc(propertyFileUri.toString());
if (dd == null) {
// Not a file we know about - see if there's a -bnd.xml on the classpath.
return super.getDeploymentDesc(propertyFileUri);
}
return dd;
}
public RuntimeDeploymentDesc getDeploymentDesc(String propertyFileName) {
String normalized = normalizePropertyFileName(propertyFileName);
RuntimeDeploymentDesc dd = deploymentDescs.get(normalized);
if (dd == null) {
String path = ddPaths.get(normalized);
if (path != null && path.length() > 0) {
try {
InputStream is = new FileInputStream(new File(path));
if (ddParserMethod == null) {
dd = RuntimeDeploymentDesc.createDeploymentDescriptor(normalized, is);
}
else {
dd = (RuntimeDeploymentDesc)ddParserMethod.invoke(null, new Object[]{normalized, is});
}
deploymentDescs.put(normalized, dd);
}
catch (Exception e) {
AnyException ex = new AnyException();
throw ex.fillInMessage(Message.ERROR_PARSING_RESOURCE_FILE, propertyFileName, e);
}
}
}
return dd;
}
public String normalizePropertyFileName(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.startsWith("file:")) { //$NON-NLS-1$
name = name.substring(5); // "file:".length()
}
int lastSlash = name.lastIndexOf('/');
if (lastSlash != -1) {
name = name.substring(lastSlash + 1);
}
if (name.endsWith("-bnd.xml")) { //$NON-NLS-1$
name = name.substring(0, name.length() - 8); // "-bnd.xml".length()
}
else if (name.endsWith(".egldd")) { //$NON-NLS-1$
name = name.substring(0, name.length() - 6); // ".egldd".length()
}
name = name.toLowerCase();
try {
return URLDecoder.decode(name, "UTF-8");
}
catch (UnsupportedEncodingException e) {
return name;
}
}
public List<String[]> parseDDArgument(String ddFiles, boolean added) {
// For simplicity there's just the one delimeter.
// name1;path1;name2;path2... using File.pathSeparator
StringTokenizer tok = new StringTokenizer(ddFiles, File.pathSeparator);
List<String[]> ddEntries = new ArrayList<String[]>();
while (tok.hasMoreTokens()) {
String name = tok.nextToken();
if (tok.hasMoreTokens()) {
String path = tok.nextToken();
try {
name = URLDecoder.decode(name, "UTF-8"); //$NON-NLS-1$
path = URLDecoder.decode(path, "UTF-8"); //$NON-NLS-1$
}
catch (UnsupportedEncodingException e) {
// Shouldn't happen.
}
ddEntries.add(new String[]{name, path});
if (added) {
addDDFile(name, path);
}
else {
removeDDFile(name);
}
}
}
return ddEntries;
}
public void addDDFile(String name, String path) {
this.ddPaths.put(name, path);
removeFromCache(name);
}
public void removeDDFile(String name) {
this.ddPaths.remove(name);
removeFromCache(name);
}
private void removeFromCache(String ddName) {
// Remove cached DDs.
if (deploymentDescs.size() > 0) {
deploymentDescs.remove(ddName);
}
// Remove cached resources. Key is a QName whose namespace is the file name.
if (BindingResourceProcessor.getBindings().size() > 0) {
for (Iterator<QName> it = BindingResourceProcessor.getBindings().keySet().iterator(); it.hasNext();) {
QName q = it.next();
if (ddName.equals(normalizePropertyFileName(q.getNamespaceURI()))) {
it.remove();
}
}
}
}
}