/******************************************************************************* * 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.ide.deployment.services.operation; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.datatools.connectivity.IConnectionProfile; import org.eclipse.datatools.connectivity.ProfileManager; import org.eclipse.edt.compiler.internal.util.EGLMessage; import org.eclipse.edt.ide.deployment.core.model.DeploymentDesc; import org.eclipse.edt.ide.deployment.internal.web.WebXML; import org.eclipse.edt.ide.deployment.internal.web.WebXMLManager; import org.eclipse.edt.ide.deployment.operation.AbstractDeploymentOperation; import org.eclipse.edt.ide.deployment.results.DeploymentResultMessageRequestor; import org.eclipse.edt.ide.deployment.results.IDeploymentResultsCollector; import org.eclipse.edt.ide.deployment.services.generators.ServiceUtilities; import org.eclipse.edt.ide.deployment.solution.DeploymentContext; import org.eclipse.edt.ide.deployment.utilities.DeploymentUtilities; import org.eclipse.edt.ide.internal.sql.util.EGLSQLUtility; import org.eclipse.edt.ide.ui.internal.util.CoreUtility; import org.eclipse.edt.javart.resources.egldd.Binding; import org.eclipse.edt.javart.resources.egldd.SQLDatabaseBinding; import org.eclipse.jst.j2ee.common.CommonFactory; import org.eclipse.jst.j2ee.common.ResAuthTypeBase; import org.eclipse.jst.j2ee.common.ResSharingScopeType; import org.eclipse.jst.j2ee.common.ResourceRef; import org.eclipse.wst.common.componentcore.ComponentCore; import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class ConfigureDataSourcesOperation extends AbstractDeploymentOperation { DeploymentResultMessageRequestor messageRequestor; private WebXML webXML; private boolean contextDotXMLUpdated; private boolean resourceRefAdded; private IProject targetProject; private Document contextDoc; private IFile contextFile; @Override public void execute(DeploymentContext context, IDeploymentResultsCollector resultsCollector, IProgressMonitor monitor) throws CoreException { messageRequestor = new DeploymentResultMessageRequestor(resultsCollector); targetProject = context.getTargetProject(); webXML = WebXMLManager.instance.getWebXMLUtil(targetProject); // 1. For JNDI bindings add a resource-ref addResourceRefs(context.getDeploymentDesc()); for (DeploymentDesc nextDD : context.getDependentModels()) { addResourceRefs(nextDD); } // 2. For the other binding types, and the server is tomcat, add/update the data source to context.xml. If // this is successful, add a corresponding resource-ref. if (ServiceUtilities.isTomcatProject(targetProject)) { updateContextDotXML(context.getDeploymentDesc()); for (DeploymentDesc nextDD : context.getDependentModels()) { updateContextDotXML(nextDD); } if (contextDotXMLUpdated) { try { saveContextDoc(); messageRequestor.addMessage(DeploymentUtilities.createEGLDeploymentInformationalMessage( EGLMessage.EGL_DEPLOYMENT_DEFINED_DATASOURCES, null, new String[] {contextFile.getName()})); } catch (Exception e) { messageRequestor.addMessage(DeploymentUtilities.createEGLDeploymentErrorMessage( EGLMessage.EGL_DEPLOYMENT_FAILED_WRITE_CONTEXTDOTXML, null, new String[] {contextFile.getName(), DeploymentUtilities.createExceptionMessage(e)})); } } } else { messageRequestor.addMessage(DeploymentUtilities.createEGLDeploymentInformationalMessage( EGLMessage.EGL_DEPLOYMENT_SERVER_NOT_TOMCAT, null, null)); } if (resourceRefAdded) { WebXMLManager.instance.updateModel(targetProject); messageRequestor.addMessage(DeploymentUtilities.createEGLDeploymentInformationalMessage( EGLMessage.EGL_DEPLOYMENT_CREATED_RESOURCE_REFS, null, null)); } } private void addResourceRefs(DeploymentDesc ddModel) { for (Binding binding : ddModel.getBindings()) { if (binding instanceof SQLDatabaseBinding) { SQLDatabaseBinding sqlBinding = (SQLDatabaseBinding)binding; if (sqlBinding.isDeployAsJndi()) { addResourceRef(sqlBinding.getJndiName(), sqlBinding.isApplicationAuthentication()); } } } } private void addResourceRef(String name, boolean applicationAuth) { if (name != null && (name = name.trim()).length() > 0) { ResourceRef ref = CommonFactory.eINSTANCE.createResourceRef(); ref.setName(name); ref.setAuth(applicationAuth ? ResAuthTypeBase.APPLICATION_LITERAL : ResAuthTypeBase.CONTAINER_LITERAL); ref.setType("javax.sql.DataSource"); ref.setResSharingScope(ResSharingScopeType.SHAREABLE_LITERAL); webXML.addResourceRef(ref); resourceRefAdded = true; } } private void updateContextDotXML(DeploymentDesc ddModel) { for (Binding binding : ddModel.getBindings()) { if (binding instanceof SQLDatabaseBinding) { SQLDatabaseBinding sqlBinding = (SQLDatabaseBinding)binding; if (!sqlBinding.isDeployAsJndi()) { continue; } // Must be hardcoded or a workspace:// URI for us to configure the data source. String jndiName = sqlBinding.getJndiName(); if (jndiName == null || (jndiName = jndiName.trim()).length() == 0) { jndiName = "jdbc/" + binding.getName(); } try { if (binding.isUseURI()) { String uri = binding.getUri(); if (uri != null && uri.startsWith("workspace://")) { IConnectionProfile profile = ProfileManager.getInstance().getProfileByName(uri.substring(12)); // "workspace://".length() if (profile != null) { configureDataSource(EGLSQLUtility.getSQLUserId(profile), EGLSQLUtility.getSQLPassword(profile), EGLSQLUtility.getSQLJDBCDriverClassPreference(profile), EGLSQLUtility.getSQLConnectionURLPreference(profile), jndiName, sqlBinding.isApplicationAuthentication()); } } } else { configureDataSource(sqlBinding.getSqlID(), sqlBinding.getSqlPassword(), sqlBinding.getSqlJDBCDriverClass(), sqlBinding.getSqlDB(), jndiName, sqlBinding.isApplicationAuthentication()); } } catch (Exception e) { messageRequestor.addMessage(DeploymentUtilities.createEGLDeploymentErrorMessage( EGLMessage.EGL_DEPLOYMENT_FAILED_DEFINE_DATASOURCE, null, new String[] {DeploymentUtilities.createExceptionMessage(e)})); } } } } private void configureDataSource(String user, String pass, String driverClass, String url, String jndiName, boolean applicationAuth) throws Exception { if (notEmpty(jndiName) && notEmpty(url) && notEmpty(driverClass)) { if (user == null) { user = ""; } if (pass == null) { pass = ""; } initContextDoc(); NodeList rootKids = contextDoc.getChildNodes(); Node contextNode = null; int rootSize = rootKids.getLength(); for (int i = 0; contextNode == null && i < rootSize; i++) { Node next = rootKids.item(i); String name = next.getNodeName(); if ("Context".equalsIgnoreCase(name)) { contextNode = next; } } if (contextNode == null) { contextNode = contextDoc.createElement("Context"); contextDoc.appendChild(contextNode); } boolean found = false; NodeList contextKids = contextNode.getChildNodes(); int kidSize = contextKids.getLength(); for (int i = 0; !found && i < kidSize; i++) { Node nextKid = contextKids.item(i); String name = nextKid.getNodeName(); if ("Resource".equalsIgnoreCase(name)) { NamedNodeMap attrs = nextKid.getAttributes(); Node nameAttr = attrs.getNamedItem("name"); if (nameAttr != null && jndiName.equals(nameAttr.getNodeValue())) { found = true; // Update any values that might have changed. updateAttr("username", user, attrs); updateAttr("password", pass, attrs); updateAttr("driverClassName", driverClass, attrs); updateAttr("url", url, attrs); updateAttr("auth", applicationAuth ? "Application" : "Container", attrs); } } } if (!found) { // Add a new entry. Node newChild = contextDoc.createElement("Resource"); NamedNodeMap attrs = newChild.getAttributes(); createAttr("name", jndiName, attrs); createAttr("username", user, attrs); createAttr("password", pass, attrs); createAttr("driverClassName", driverClass, attrs); createAttr("url", url, attrs); createAttr("maxActive", "4", attrs); createAttr("maxIdle", "2", attrs); createAttr("maxWait", "5000", attrs); createAttr("auth", applicationAuth ? "Application" : "Container", attrs); createAttr("type", "javax.sql.DataSource", attrs); contextNode.appendChild(newChild); contextDotXMLUpdated = true; } } } private void updateAttr(String name, String value, NamedNodeMap attrs) { Node attr = attrs.getNamedItem(name); if (attr == null) { attr = contextDoc.createAttribute(name); attrs.setNamedItem(attr); attr.setNodeValue(value); contextDotXMLUpdated = true; } else if (!value.equals(attr.getNodeValue())) { attr.setNodeValue(value); contextDotXMLUpdated = true; } } private void createAttr(String name, String value, NamedNodeMap attrs) { Attr attr = contextDoc.createAttribute(name); attr.setValue(value); attrs.setNamedItem(attr); } private boolean notEmpty(String value) { return value != null && value.trim().length() != 0; } private IFile getContextDotXMLFile(IProject project) throws CoreException { IVirtualComponent component = ComponentCore.createComponent(project); IFolder metaInfFolder = project.getFolder(component.getRootFolder().getFolder("META-INF").getProjectRelativePath()); if (!metaInfFolder.exists()) { CoreUtility.createFolder(metaInfFolder, true, true, null); } return metaInfFolder.getFile("context.xml"); } private void initContextDoc() throws Exception { if (contextDoc == null) { DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); contextFile = getContextDotXMLFile(targetProject); if (!contextFile.exists()) { contextDoc = docBuilder.newDocument(); } else { contextDoc = docBuilder.parse(contextFile.getContents(true)); } } } private void saveContextDoc() throws Exception { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); StreamResult result = new StreamResult(new StringWriter()); transformer.transform(new DOMSource(contextDoc), result); String contents = result.getWriter().toString(); ByteArrayInputStream inputStream; try { String encoding = contextDoc.getXmlEncoding(); if (encoding == null || encoding.length() == 0) { encoding = "UTF-8"; } inputStream = new ByteArrayInputStream(contents.getBytes(encoding)); } catch (UnsupportedEncodingException e) { inputStream = new ByteArrayInputStream(contents.getBytes()); } try { if (!contextFile.exists()) { contextFile.create(inputStream, true, null); } else { contextFile.setContents(inputStream, true, true, null); } } finally { try { inputStream.close(); } catch (IOException e) { } } } }