/*******************************************************************************
* Copyright © 2012, 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.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.namespace.QName;
import org.eclipse.edt.javart.messages.Message;
import org.eclipse.edt.javart.resources.egldd.Binding;
import org.eclipse.edt.javart.resources.egldd.RuntimeDeploymentDesc;
import org.eclipse.edt.javart.resources.egldd.SQLDatabaseBinding;
import org.eclipse.edt.runtime.java.eglx.lang.EDictionary;
import resources.edt.binding.BindingResourceProcessor;
import eglx.java.JavaObjectException;
import eglx.lang.AnyException;
import eglx.lang.Resources.ResourceLocator;
import eglx.persistence.sql.SQLDataSource;
import eglx.persistence.sql.SQLJNDIDataSource;
public class IDEBindingResourceProcessor extends BindingResourceProcessor {
/**
* The name of the default DD file.
*/
private URI defaultDD;
/**
* URL on which the IDE server is running.
*/
private final String ideURL;
public IDEBindingResourceProcessor(int idePort, IDEResourceLocator resourceLocator) {
this.resourceLocator = resourceLocator;
this.ideURL = "http://localhost:" + idePort + "/__testServer"; //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
protected Binding getBinding(String bindingURI, URI propertyFileURI, ResourceLocator resourceLocator) {
// This is a little different than super's implementation. Each binding is cached based on the DD that
// it resides within, instead of the DD being requested. Otherwise the cache is not properly cleared
// when modifying an imported binding.
QName resourceId = new QName(propertyFileURI.toASCIIString(), bindingURI);
Binding binding = bindings.get(resourceId);
if (binding == null) {
RuntimeDeploymentDesc dd = getDeploymentDesc(propertyFileURI, resourceLocator);
binding = getBinding(bindingURI, dd);
if (binding != null) {
bindings.put(resourceId, binding);
}
else {
String normalizedName;
if (resourceLocator instanceof IDEResourceLocator) {
normalizedName = ((IDEResourceLocator)resourceLocator).normalizePropertyFileName(propertyFileURI.toString());
}
else {
normalizedName = dd.getName();
}
Set<String> seenDDs = new HashSet<String>();
seenDDs.add(normalizedName);
binding = getBinding(bindingURI, dd.getIncludedDescs(), resourceLocator, seenDDs);
}
}
return binding;
}
@Override
protected Binding getBinding(String name, List<String> includes, ResourceLocator resourceLocator, Set<String> seenDDs) throws AnyException {
// This is a little different than super's implementation. Each binding is cached based on the DD that
// it resides within, instead of the DD being requested. Otherwise the cache is not properly cleared
// when modifying an imported binding.
List<RuntimeDeploymentDesc> includedDDs = new ArrayList<RuntimeDeploymentDesc>();
for (String ddName : includes) {
try {
URI uri = createFileURI(ddName);
String normalizedName;
if (resourceLocator instanceof IDEResourceLocator) {
normalizedName = ((IDEResourceLocator)resourceLocator).normalizePropertyFileName(uri.toString());
}
else {
normalizedName = ddName;
}
if (seenDDs.contains(normalizedName)) {
continue;
}
seenDDs.add(normalizedName);
QName resourceId = new QName(uri.toASCIIString(), name);
Binding binding = bindings.get(resourceId);
if (binding != null) {
return binding;
}
RuntimeDeploymentDesc includedDD = getDeploymentDesc(uri, resourceLocator);
binding = getBinding(name, includedDD);
if (binding != null) {
bindings.put(resourceId, binding);
return binding;
}
else {
includedDDs.add(includedDD);
}
} catch (URISyntaxException e) {
JavaObjectException jox = new JavaObjectException();
jox.exceptionType = URI.class.getName();
jox.initCause( e );
throw jox.fillInMessage( Message.RESOURCE_URI_EXCEPTION, ddName );
}
}
for (RuntimeDeploymentDesc includedDD : includedDDs){
Binding binding = getBinding(name, includedDD.getIncludedDescs(), resourceLocator, seenDDs);
if (binding != null) {
return binding;
}
}
return null;
}
@Override
protected Object getResource(Binding binding, URI dd) throws AnyException {
if (binding instanceof SQLDatabaseBinding) {
SQLDatabaseBinding sqlBinding = (SQLDatabaseBinding)binding;
if (sqlBinding.isUseURI()) {
String uri = sqlBinding.getUri();
if (uri != null && uri.startsWith("workspace://")) { //$NON-NLS-1$
if (sqlBinding.isDeployAsJndi()) {
String jndiName = sqlBinding.getJndiName();
if (jndiName != null && (jndiName = jndiName.trim()).length() > 0) {
EDictionary props = null;
if (sqlBinding.isApplicationAuthentication()) {
SQLConnectionInfo info = getParsedConnectionProfileSettings(uri.substring(12)); // "workspace://".length()
if (info != null) {
props = new EDictionary();
if (info.username != null && info.username.length() > 0) {
props.put("user", info.username); //$NON-NLS-1$
}
if (info.password != null && info.password.length() > 0) {
props.put("password", info.password); //$NON-NLS-1$
}
}
}
return new SQLJNDIDataSource(jndiName, props);
}
else {
System.err.println("WARN: jndiName parameter missing for resource binding " + sqlBinding.getName() + ". JNDI connection will NOT be used"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
SQLConnectionInfo info = getParsedConnectionProfileSettings(uri.substring(12)); // "workspace://".length()
if (info != null) {
EDictionary props = new EDictionary();
if (info.username != null && info.username.length() > 0) {
props.put("user", info.username); //$NON-NLS-1$
}
if (info.password != null && info.password.length() > 0) {
props.put("password", info.password); //$NON-NLS-1$
}
// Try to load the class so that it registers itself, in case it's not a Type 4 driver.
// This must be done before any connection is made, such as by invoking setCurrentSchema below.
if (info.driverClass != null && info.driverClass.length() > 0) {
try {
Class.forName(info.driverClass);
}
catch (Throwable t) {
}
}
SQLDataSource ds = new SQLDataSource(info.url, props);
if (info.defaultSchema != null && info.defaultSchema.length() > 0) {
ds.setCurrentSchema(info.defaultSchema);
}
return ds;
}
}
}
else if (sqlBinding.isDeployAsJndi()) {
String jndiName = sqlBinding.getJndiName();
if (jndiName != null && (jndiName = jndiName.trim()).length() > 0) {
EDictionary props = null;
if (sqlBinding.isApplicationAuthentication()) {
props = new EDictionary();
String user = sqlBinding.getSqlID();
String pass = sqlBinding.getSqlPassword();
if (user.length() > 0) {
props.put("user", user); //$NON-NLS-1$
}
if (pass.length() > 0) {
props.put("password", pass); //$NON-NLS-1$
}
}
return new SQLJNDIDataSource(jndiName, props);
}
else {
System.err.println("WARN: jndiName parameter missing for resource binding " + sqlBinding.getName() + ". JNDI connection will NOT be used"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
return super.getResource(binding, dd);
}
@Override
protected URI getDefaultDDURI() {
if (defaultDD == null) {
AnyException ae = new AnyException();
throw ae.fillInMessage( Message.MISSING_DEFAULT_DD );
}
return defaultDD;
}
public void setDefaultDD(String dd) throws AnyException {
if (dd == null || (dd = dd.trim()).length() == 0) {
this.defaultDD = null;
}
else {
try {
try {
dd = URLEncoder.encode(dd, "UTF-8");
}
catch (UnsupportedEncodingException e) {
}
this.defaultDD = createFileURI(dd);
} catch (URISyntaxException e) {
JavaObjectException jox = new JavaObjectException();
jox.exceptionType = URI.class.getName();
jox.initCause( e );
throw jox.fillInMessage( Message.RESOURCE_URI_EXCEPTION, defaultDD );
}
}
}
public IDEResourceLocator getResourceLocator() {
return (IDEResourceLocator)resourceLocator;
}
/**
* @return the connection settings as a parsed, decoded array; values are: url, username, password, default schema, driver class name.
*/
public SQLConnectionInfo getParsedConnectionProfileSettings(String profileName) {
String profileInfo = getConnectionProfileSettings(profileName);
if (profileInfo != null && profileInfo.length() > 0) {
String[] tokens = profileInfo.split(";"); //$NON-NLS-1$
if (tokens.length > 0) {
String url = tokens[0].trim();
String user = null;
String pass = null;
String schema = null;
String className = null;
if (tokens.length > 1) {
user = tokens[1].trim();
}
if (tokens.length > 2) {
pass = tokens[2].trim();
}
if (tokens.length > 3) {
schema = tokens[3].trim();
}
if (tokens.length > 4) {
className = tokens[4].trim();
}
try {
url = URLDecoder.decode(url, "UTF-8"); //$NON-NLS-1$
if (user != null) {
user = URLDecoder.decode(user, "UTF-8"); //$NON-NLS-1$
}
if (pass != null) {
pass = URLDecoder.decode(pass, "UTF-8"); //$NON-NLS-1$
}
if (schema != null) {
schema = URLDecoder.decode(schema, "UTF-8"); //$NON-NLS-1$
}
if (className != null) {
className = URLDecoder.decode(className, "UTF-8"); //$NON-NLS-1$
}
}
catch (UnsupportedEncodingException e) {
// Shouldn't happen.
}
SQLConnectionInfo info = new SQLConnectionInfo();
info.url = url;
info.username = user;
info.password = pass;
info.defaultSchema = schema;
info.driverClass = className;
return info;
}
}
return null;
}
/**
* @return the connection settings for the connection profile. A connection to the IDE is used to dynamically obtain this information.
*/
private String getConnectionProfileSettings(String profileName) {
String connectionURL = null;
InputStream is = null;
try {
HttpURLConnection conn = (HttpURLConnection)new URL(ideURL).openConnection(); //$NON-NLS-1$ //$NON-NLS-2$
conn.setDoOutput(true);
conn.setRequestProperty("Accept-Charset", "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$
OutputStream output = null;
try {
output = conn.getOutputStream();
output.write(("connectionProfile=" + profileName).getBytes("UTF-8")); //$NON-NLS-1$ //$NON-NLS-2$
}
finally {
if (output != null) {
try {
output.close();
}
catch (IOException e) {
}
}
}
if (conn.getResponseCode() == 200) {
is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder buf = new StringBuilder( 50 );
String line;
while ((line = br.readLine()) != null) {
buf.append(line);
}
connectionURL = buf.toString();
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (is != null) {
try {
is.close();
}
catch (IOException e) {
}
}
}
return connectionURL;
}
public static class SQLConnectionInfo {
public String username;
public String password;
public String driverClass;
public String url;
public String defaultSchema;
}
}