Project: libra
/*******************************************************************************
 * Copyright (c) 2010, 2011 SAP AG 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: 
 *     Stefan Dimov (SAP AG) - initial API and implementation 
 *     Kaloyan Raev (SAP AG) 
 *******************************************************************************/
package org.eclipse.libra.facet.test; 
 
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.VIRTUAL_COMPONENT_PATH; 
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.WEB_CONTEXT_PATH_HEADER; 
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.getContextRootFromPDEModel; 
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.getContextRootFromWTPModel; 
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.setContextRootInPDEModel; 
import static org.eclipse.libra.facet.OSGiBundleFacetUtils.setContextRootInWTPModel; 
import static org.eclipse.wst.common.tests.OperationTestCase.deleteAllProjects; 
import static org.eclipse.wst.common.tests.OperationTestCase.waitOnJobs; 
 
import java.io.BufferedReader; 
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
 
import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerException; 
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.IProject; 
import org.eclipse.core.resources.IResource; 
import org.eclipse.core.runtime.CoreException; 
import org.eclipse.core.runtime.NullProgressMonitor; 
import org.eclipse.core.runtime.Path; 
import org.eclipse.wst.common.project.facet.core.FacetedProjectFramework; 
import org.eclipse.wst.common.project.facet.core.IFacetedProjectWorkingCopy; 
import org.junit.After; 
import org.junit.Assert; 
import org.junit.Before; 
import org.junit.Test; 
import org.w3c.dom.Attr; 
import org.w3c.dom.Document; 
import org.w3c.dom.Element; 
import org.w3c.dom.NamedNodeMap; 
import org.w3c.dom.NodeList; 
import org.xml.sax.SAXException; 
 
public class WebContextRootSynchronizerTest { 
  
 private static final String APPEND = "Changed";  
  
 private static int MAX_ATTEMPTS = 20
  
 private String expectedWebContextRoot; 
 private IProject wabProject; 
  
 @Before 
 public void importProject() throws Exception { 
  // clean up the workspace 
  deleteAllProjects(); 
  waitOnJobs(); 
  // create new WAB project 
  String projectName = "TestWAB" + System.currentTimeMillis(); 
  expectedWebContextRoot = '/' + projectName + APPEND; 
  wabProject = createWabProject(projectName); 
  waitOnJobs(); 
 
  
 @After 
 public void waitJobs() throws Exception { 
  // Wait for all validation jobs to end before ending test.... 
  waitOnJobs(); 
 
  
 @Test 
 public void testPDEChangeLeadsToWTPChange() throws Exception {   
     String newPDEWebContextPath = getContextRootFromPDEModel(wabProject) + APPEND; 
     setContextRootInPDEModel(wabProject, newPDEWebContextPath, null); 
     checkModels(wabProject, expectedWebContextRoot); 
 
  
 @Test 
 public void testWTPChangeLeadsToPDEChange() throws Exception { 
     String newWTPWebContextPath = getContextRootFromWTPModel(wabProject) + APPEND; 
     setContextRootInWTPModel(wabProject, newWTPWebContextPath);          
     checkModels(wabProject, expectedWebContextRoot); 
 
  
 @Test 
 public void testSettingsFileChangeLeadsToModelChange() throws Exception { 
  String newWTPWebContextPath = getContextRootFromWTPModel(wabProject) + APPEND; 
  setWebContextRootInSettings(wabProject, newWTPWebContextPath); 
  checkModels(wabProject, expectedWebContextRoot); 
 
  
 @Test 
 public void testManifetsFileChangeLeadsToModelChange() throws Exception { 
  String newPDEWebContextPath = getContextRootFromPDEModel(wabProject) + APPEND; 
  setWebContextRootInManifest(wabProject, newPDEWebContextPath); 
     checkModels(wabProject, expectedWebContextRoot); 
 }  
  
 @Test 
 public void testRemoveWebContextRootFromPDEModel() throws Exception { 
  setContextRootInPDEModel(wabProject, nullnull); 
     checkModels(wabProject, null); 
 }  
  
 @Test 
 public void testRemoveWebContextRootFromWTPModel() throws Exception { 
  setContextRootInWTPModel(wabProject, null); 
     checkModels(wabProject, null); 
 }  
  
  
 // ------------------------------ private helper methods ---------------------------------------------- 
  
 private IProject createWabProject(String projectName) throws CoreException { 
  IFacetedProjectWorkingCopy wc = FacetedProjectFramework.createNewProject(); 
  wc.setProjectName(projectName); 
  wc.setSelectedPreset("osgi.web.bundle.preset"); 
  wc.commitChanges(null); 
  return wc.getProject(); 
 
  
 private boolean areModelsEqualToTheExpectedValue(IProject project, String expectedWebContextRoot) throws CoreException { 
  String pdeWebContextPath = getContextRootFromPDEModel(project); 
  String wtpWebContextPath = getContextRootFromWTPModel(project); 
   
  if (expectedWebContextRoot == null) { 
   return pdeWebContextPath == null && wtpWebContextPath == null
  else { 
   return expectedWebContextRoot.equals(pdeWebContextPath) && expectedWebContextRoot.equals(wtpWebContextPath);  
  
 }  
  
 private void checkModels(IProject wabProject, String expectedWebContextRoot) throws CoreException { 
  boolean equal = false
      
     for (int attempt = 0; attempt < MAX_ATTEMPTS && !equal; attempt++) {       
      equal = areModelsEqualToTheExpectedValue(wabProject, expectedWebContextRoot); 
      if (!equal) { 
       // we need to wait for the other model to refresh 
       wabProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); 
       try { 
        Thread.sleep(1000);// 1 second 
       catch (InterruptedException iexc) { 
        System.out.println("Interrupted exception caught. Checking once more."); 
        wabProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); 
        equal = areModelsEqualToTheExpectedValue(wabProject, expectedWebContextRoot); 
       
      
     }            
 
     // check that both models are set to the new context root 
     Assert.assertEquals(expectedWebContextRoot, getContextRootFromPDEModel(wabProject)); 
     Assert.assertEquals(expectedWebContextRoot, getContextRootFromWTPModel(wabProject)); 
 
  
 private void setWebContextRootInSettings(IProject wabProject, String newValue) throws ParserConfigurationException, SAXException, IOException, TransformerException, CoreException { 
  IFile settingsFile = wabProject.getFile(VIRTUAL_COMPONENT_PATH); 
  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
  DocumentBuilder db = dbf.newDocumentBuilder(); 
   
  Document xmlDocument = db.parse(settingsFile.getContents()); 
  changeWebContextRootFromSettings(xmlDocument, newValue); 
     
  InputStream is = new ByteArrayInputStream(saveDomToBytes(xmlDocument)); 
  settingsFile.setContents(is, IResource.KEEP_HISTORY | IResource.FORCE, null); 
 
 
 private Element getWebModuleElement(Document xmlDocument) { 
  Element root = xmlDocument.getDocumentElement(); 
  NodeList children = root.getElementsByTagName("wb-module"); 
  Element webModuleElem = (Element)children.item(0); 
  return webModuleElem; 
 
 
 private Element getContextRootProperty(Element webModuleElement) { 
  NodeList webModuleElementProperties = webModuleElement.getElementsByTagName("property"); 
  for (int i = 0; i < webModuleElementProperties.getLength(); i++) { 
   Element property = (Element) webModuleElementProperties.item(i); 
   NamedNodeMap attributes = property.getAttributes(); 
   Attr nameAttribute = (Attr) attributes.getNamedItem("name"); 
   if (nameAttribute.getNodeValue().equals("context-root")) { 
    return property; 
   
  
  return null
 
 
 private Attr getValueAttribute(Element contextRootProperty) { 
  NamedNodeMap attributes = contextRootProperty.getAttributes(); 
  Attr valueAttribute = (Attr) attributes.getNamedItem("value"); 
  if (valueAttribute != null) { 
   return valueAttribute; 
  
  return null
 
 
 private void changeWebContextRootFromSettings(Document xmlDocument, String newValue) { 
  Element webModuleElement = getWebModuleElement(xmlDocument); 
  Element contextRootProperty = getContextRootProperty(webModuleElement); 
  Attr valueAttribute = getValueAttribute(contextRootProperty); 
  valueAttribute.setNodeValue(newValue); 
 
  
 private byte[] saveDomToBytes(Document xmlDocument) throws TransformerException { 
  ByteArrayOutputStream os = new ByteArrayOutputStream(); 
   
  TransformerFactory transformerFactory = TransformerFactory.newInstance(); 
  Transformer transformer = transformerFactory.newTransformer(); 
  transformer.transform(new DOMSource(xmlDocument), new StreamResult(os)); 
   
  return os.toByteArray(); 
 
 
 private void setWebContextRootInManifest(IProject wabProject, String newContextRoot) throws CoreException, IOException { 
  IFile manifestFile = wabProject.getFile(new Path("WebContent/META-INF/MANIFEST.MF")); 
  ByteArrayOutputStream os = new ByteArrayOutputStream(); 
  PrintWriter pw = new PrintWriter(os); 
   
  BufferedReader reader = new BufferedReader(new InputStreamReader(manifestFile.getContents())); 
  String line; 
  while ((line = reader.readLine()) != null) { 
   if (line.startsWith(WEB_CONTEXT_PATH_HEADER)) { 
    pw.println(WEB_CONTEXT_PATH_HEADER + ": " + newContextRoot); 
   else { 
    pw.println(line); 
   
  
   
  pw.flush(); 
   
  InputStream is = new ByteArrayInputStream(os.toByteArray()); 
  manifestFile.setContents(is, IResource.KEEP_HISTORY | IResource.FORCE, null); 
 
 
}