/******************************************************************************* * Copyright (c) 2008, 2012 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 * bug:244839 - eugene@genuitec.com * * Provisional API: This class/interface is part of an interim API that is still under development and expected to * change significantly before reaching stability. It is being made available at this early stage to solicit feedback * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken * (repeatedly) as the API evolves. * * *******************************************************************************/ package org.eclipse.wst.jsdt.web.core.javascript; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.List; import java.util.Vector; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.wst.jsdt.core.IBuffer; import org.eclipse.wst.jsdt.core.IJavaScriptElement; import org.eclipse.wst.jsdt.core.IJavaScriptProject; import org.eclipse.wst.jsdt.core.IJavaScriptUnit; import org.eclipse.wst.jsdt.core.IPackageFragmentRoot; import org.eclipse.wst.jsdt.core.ISourceRange; import org.eclipse.wst.jsdt.core.JavaScriptModelException; import org.eclipse.wst.jsdt.core.WorkingCopyOwner; import org.eclipse.wst.jsdt.core.compiler.IProblem; import org.eclipse.wst.jsdt.internal.core.DocumentContextFragmentRoot; import org.eclipse.wst.jsdt.internal.core.Member; import org.eclipse.wst.jsdt.internal.core.SourceRefElement; import org.eclipse.wst.jsdt.web.core.internal.Logger; import org.eclipse.wst.jsdt.web.core.internal.project.JsWebNature; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.provisional.IModelManager; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; /** * * Provisional API: This class/interface is part of an interim API that is still under development and expected to * change significantly before reaching stability. It is being made available at this early stage to solicit feedback * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken * (repeatedly) as the API evolves. */ public class JsTranslation implements IJsTranslation { private static final boolean DEBUG; static { String value = Platform.getDebugOption("org.eclipse.wst.jsdt.web.core/debug/jstranslation"); //$NON-NLS-1$ DEBUG = value != null && value.equalsIgnoreCase("true"); //$NON-NLS-1$ } private IJavaScriptUnit fCompilationUnit = null; private DocumentContextFragmentRoot fDocumentScope; private IJavaScriptProject fJavaProject = null; private byte[] fLock = null; private IProgressMonitor fProgressMonitor = null; protected IStructuredDocument fHtmlDocument; protected String fModelBaseLocation; // private static final String SUPER_TYPE_NAME = "Window"; //$NON-NLS-1$ // private static final String SUPER_TYPE_LIBRARY = "org.eclipse.wst.jsdt.launching.baseBrowserLibrary"; //$NON-NLS-1$ protected IJsTranslator fTranslator; private String mangledName; protected boolean listenForChanges; public JsTranslation() { /* do nothing */ } public IJsTranslator getTranslator() { if(fTranslator!=null) { return fTranslator; } fTranslator = new JsTranslator(fHtmlDocument, fModelBaseLocation, listenForChanges); return this.fTranslator; } protected JsTranslation(IStructuredDocument htmlDocument, IJavaScriptProject javaProj, boolean listenForChanges) { fLock = new byte[0]; fJavaProject = javaProj; fHtmlDocument = htmlDocument; setBaseLocation(); mangledName = createMangledName(); this.listenForChanges=listenForChanges; } public IJsTranslation getInstance(IStructuredDocument htmlDocument, IJavaScriptProject javaProj, boolean listenForChanges) { return new JsTranslation(htmlDocument,javaProj, listenForChanges); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getJavaProject() */ public IJavaScriptProject getJavaProject() { return fJavaProject; } private IPackageFragmentRoot getDocScope(boolean reset) { if (fDocumentScope == null) { // IProject project = getJavaProject().getProject(); // IResource absoluteRoot = // ((IContainer)getJavaProject().getResource()).findMember( // WebRootFinder.getWebContentFolder(fJavaProject.getProject())); fDocumentScope = new DocumentContextFragmentRoot(fJavaProject, getFile(), WebRootFinder.getWebContentFolder(fJavaProject.getProject()), WebRootFinder.getServerContextRoot(fJavaProject.getProject()), JsWebNature.VIRTUAL_SCOPE_ENTRY); fDocumentScope.setIncludedFiles(getTranslator().getRawImports()); return fDocumentScope; } if (reset) fDocumentScope.setIncludedFiles(getTranslator().getRawImports()); return fDocumentScope; } private void setBaseLocation() { IDOMModel xmlModel = null; try { IModelManager modelManager = StructuredModelManager.getModelManager(); xmlModel = (IDOMModel) modelManager.getExistingModelForRead(fHtmlDocument); if (xmlModel == null) { xmlModel = (IDOMModel) modelManager.getModelForRead(fHtmlDocument); } if(xmlModel != null) { fModelBaseLocation = xmlModel.getBaseLocation(); } } finally { if (xmlModel != null) xmlModel.releaseFromRead(); } // return xmlModel; } public IFile getFile() { return FileBuffers.getWorkspaceFileAtLocation(new Path(fModelBaseLocation)); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getHtmlDocument() */ public IDocument getHtmlDocument() { return fHtmlDocument; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getMissingTagStart() */ public int getMissingTagStart() { return getTranslator().getMissingEndTagRegionStart(); } public int getJavaScriptOffset(int indexOf) { return ((JsTranslator)getTranslator()).getJavaScriptOffset(indexOf); } public int getWebPageOffset(int indexOf) { return ((JsTranslator)getTranslator()).getWebOffset(indexOf); } private String getWebRoot() { return WebRootFinder.getWebContentFolder(fJavaProject.getProject()).toString(); } public String getDirectoryUnderRoot() { String webRoot = getWebRoot(); IPath projectWebRootPath = getJavaProject().getPath().append(webRoot); IPath filePath = new Path(fModelBaseLocation).removeLastSegments(1); return filePath.removeFirstSegments(projectWebRootPath.matchingFirstSegments(filePath)).toString(); } /** * Originally from ReconcileStepForJava. Creates an IJavaScriptUnit from * the contents of the JSP document. * * @return an IJavaScriptUnit from the contents of the JSP document */ private IJavaScriptUnit createCompilationUnit() throws JavaScriptModelException { IPackageFragmentRoot root = getDocScope(true); IJavaScriptUnit cu = root.getPackageFragment("").getJavaScriptUnit(getMangledName() + JsDataTypes.BASE_FILE_EXTENSION).getWorkingCopy(getWorkingCopyOwner(), getProgressMonitor()); //$NON-NLS-1$ IBuffer buffer; try { buffer = cu.getBuffer(); } catch (JavaScriptModelException e) { e.printStackTrace(); buffer = null; } if (buffer != null) { getTranslator().setBuffer(buffer); } return cu; } public String fixupMangledName(String displayString) { if (displayString == null) { return null; } return displayString.replaceAll(getMangledName() + ".js", getHtmlPageName()); //$NON-NLS-1$ } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getAllElementsInJsRange(int, int) */ public IJavaScriptElement[] getAllElementsInJsRange(int javaPositionStart, int javaPositionEnd) { IJavaScriptElement[] EMTPY_RESULT_SET = new IJavaScriptElement[0]; IJavaScriptElement[] result = EMTPY_RESULT_SET; IJavaScriptElement[] allChildren = null; try { allChildren = getCompilationUnit().getChildren(); } catch (JavaScriptModelException e) { } Vector validChildren = new Vector(); for (int i = 0; i < allChildren.length; i++) { ISourceRange range = getJSSourceRangeOf(allChildren[i]); if (javaPositionStart <= range.getOffset() && range.getLength() + range.getOffset() <= (javaPositionEnd)) { validChildren.add(allChildren[i]); } else if (allChildren[i].getElementType() == IJavaScriptElement.TYPE) { validChildren.add(allChildren[i]); } } if (validChildren.size() > 0) { result = (IJavaScriptElement[]) validChildren.toArray(new IJavaScriptElement[]{}); } if (result == null || result.length == 0) { return EMTPY_RESULT_SET; } return result; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getCompilationUnit() */ public IJavaScriptUnit getCompilationUnit() { // Genuitec Begin Fix 6149: Exception opening external HTML file if (!getJavaProject().exists()) { return null; } // Genuitec End Fix 6149: Exception opening external HTML file synchronized (fLock) { try { if (fCompilationUnit == null) { fCompilationUnit = createCompilationUnit(); return fCompilationUnit; } } catch (JavaScriptModelException jme) { if (JsTranslation.DEBUG) { Logger.logException("error creating JSP working copy... ", jme); //$NON-NLS-1$ } } } getDocScope(true); try { fCompilationUnit = fCompilationUnit.getWorkingCopy(getWorkingCopyOwner(), getProgressMonitor()); // fCompilationUnit.makeConsistent(getProgressMonitor()); } catch (JavaScriptModelException ex) { // TODO Auto-generated catch block ex.printStackTrace(); } return fCompilationUnit; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getElementsFromJsRange(int, int) */ public IJavaScriptElement[] getElementsFromJsRange(int javaPositionStart, int javaPositionEnd) { IJavaScriptElement[] EMTPY_RESULT_SET = new IJavaScriptElement[0]; IJavaScriptElement[] result = EMTPY_RESULT_SET; try { IJavaScriptUnit cu = getCompilationUnit(); if (cu != null) { synchronized (fLock) { int cuDocLength = cu.getBuffer().getLength(); int javaLength = javaPositionEnd - javaPositionStart; if (cuDocLength > 0 && javaPositionStart >= 0 && javaLength >= 0 && javaPositionEnd <= cuDocLength) { result = cu.codeSelect(javaPositionStart, javaLength, getWorkingCopyOwner()); } } } if (result == null || result.length == 0) { return EMTPY_RESULT_SET; } } catch (JavaScriptModelException x) { Logger.logException(x); } return result; } /** * @deprecated */ public IJavaScriptElement[] getElementsFromWebRange(int webPositionStart, int webPositionEnd) { int javaScriptPositionStart = getJavaScriptOffset(webPositionStart); int javaScriptPositionEnd = getJavaScriptOffset(webPositionEnd); if (javaScriptPositionStart < 0 || javaScriptPositionEnd < 0) return new IJavaScriptElement[0]; return getElementsFromJsRange(javaScriptPositionStart, javaScriptPositionEnd); } private String getHtmlPageName() { IPath path = new Path(fModelBaseLocation); return path.lastSegment(); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getHtmlText() */ public String getHtmlText() { return fHtmlDocument.get(); } public String getJavaPath() { IPath rootPath = new Path(fModelBaseLocation).removeLastSegments(1); String cuPath = rootPath.append("/" + getMangledName() + JsDataTypes.BASE_FILE_EXTENSION).toString(); //$NON-NLS-1$ return cuPath; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getJsElementAtOffset(int) */ public IJavaScriptElement getJsElementAtOffset(int jsOffset) { IJavaScriptElement elements = null; try { elements = getCompilationUnit().getElementAt(jsOffset); } catch (JavaScriptModelException e) { // TODO Auto-generated catch block if (JsTranslation.DEBUG) { Logger.logException("error retrieving java elemtnt from compilation unit... ", e); //$NON-NLS-1$ } // } } return elements; } private ISourceRange getJSSourceRangeOf(IJavaScriptElement element) { // returns the offset in html of given element ISourceRange range = null; if (element instanceof Member) { try { range = ((Member) element).getNameRange(); } catch (JavaScriptModelException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else if (element instanceof SourceRefElement) { try { range = ((SourceRefElement) element).getSourceRange(); } catch (JavaScriptModelException e) { e.printStackTrace(); } } return range; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getJsText() */ public String getJsText() { return getTranslator().getJsText(); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getScriptPositions() */ public Position[] getScriptPositions() { return getTranslator().getHtmlLocations(); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#insertInFirstScriptRegion(java.lang.String) */ public void insertInFirstScriptRegion(String text) { Position pos[] = getScriptPositions(); int scriptStartOffset = 0; if(pos!=null && pos.length>0) { scriptStartOffset = pos[0].getOffset(); } String insertText = (scriptStartOffset==0?"":"\n") + text; insertScript(scriptStartOffset,insertText); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#insertScript(int, java.lang.String) */ public void insertScript(int offset, String text) { IDOMModel xmlModel = null; Position[] inHtml = getScriptPositions(); boolean isInsideExistingScriptRegion = false; for (int i = 0; i < inHtml.length; i++) { if (inHtml[i].overlapsWith(offset, 1)) { // * inserting into a script region isInsideExistingScriptRegion = true; } } String insertText = null; if (isInsideExistingScriptRegion) { insertText = text; } else { insertText = offset != 0 ? "\n" : "" + "<script type=\"text/javascript\">\n" + text + "\n</script>\n"; } // translator.documentAboutToBeChanged(null); synchronized (fLock) { try { xmlModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForEdit(fHtmlDocument); if (xmlModel == null) { xmlModel = (IDOMModel) StructuredModelManager.getModelManager().getModelForEdit(fHtmlDocument); } if (xmlModel != null) { xmlModel.aboutToChangeModel(); xmlModel.getDocument().getStructuredDocument().replaceText(this, offset, 0, insertText); xmlModel.changedModel(); try { xmlModel.save(); } catch (UnsupportedEncodingException e) {} catch (IOException e) {} catch (CoreException e) {} } } finally { if (xmlModel != null) xmlModel.releaseFromEdit(); } } // translator.documentChanged(null); } public String getMangledName() { return this.mangledName; } private String createMangledName() { return JsNameManglerUtil.mangle(fModelBaseLocation); } /** * * @return the problem requestor for the JavaScriptUnit in this * JsTranslation */ private JsProblemRequestor getProblemRequestor() { return CompilationUnitHelper.getInstance().getProblemRequestor(); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#getProblems() */ public List getProblems() { List problemList = getProblemRequestor().getCollectedProblems(); getProblemRequestor().endReporting(); IProblem[] problems = null; if (problemList == null) problems = new IProblem[0]; else problems = (IProblem[]) problemList.toArray(new IProblem[problemList.size()]); IJsTranslator translator = getTranslator(); if (translator instanceof JsTranslator && problems.length > 0) { Region[] generatedRanges = ((JsTranslator) translator).getGeneratedRanges(); for (int i = 0; i < problems.length; i++) { for (int j = 0; j < generatedRanges.length; j++) { // remove any problems that are fully reported within a region generated by the translator if (problems[i].getSourceStart() >= generatedRanges[j].getOffset() && problems[i].getSourceEnd() <= (generatedRanges[j].getOffset() + generatedRanges[j].getLength())) { problemList.remove(problems[i]); } } } } return problemList; } private IProgressMonitor getProgressMonitor() { if (fProgressMonitor == null) { fProgressMonitor = new NullProgressMonitor(); } return fProgressMonitor; } public WorkingCopyOwner getWorkingCopyOwner() { return CompilationUnitHelper.getInstance().getWorkingCopyOwner(); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#ifOffsetInImportNode(int) */ public boolean ifOffsetInImportNode(int offset) { Position[] importRanges = getTranslator().getImportHtmlRanges(); for (int i = 0; i < importRanges.length; i++) { if (importRanges[i].includes(offset)) { return true; } } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#reconcileCompilationUnit() */ public void reconcileCompilationUnit() { // if(true) return; IJavaScriptUnit cu = getCompilationUnit(); if (fCompilationUnit == null) { return; } if (cu != null) { try { synchronized (fLock) { // clear out old validation messages WorkingCopyOwner workingCopyOwner = getWorkingCopyOwner(); JsProblemRequestor problemRequestor = (JsProblemRequestor) workingCopyOwner.getProblemRequestor(cu.getWorkingCopy(getProgressMonitor())); if(problemRequestor != null && problemRequestor.getCollectedProblems() != null) problemRequestor.getCollectedProblems().clear(); cu.reconcile(IJavaScriptUnit.NO_AST, true, true, getWorkingCopyOwner(), getProgressMonitor()); } } catch (JavaScriptModelException e) { Logger.logException(e); } } } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#release() */ public void release() { if (getTranslator() != null) getTranslator().release(); synchronized (fLock) { if (fCompilationUnit != null) { try { if (JsTranslation.DEBUG) { System.out.println("------------------------------------------------------------------"); //$NON-NLS-1$ System.out.println("(-) JsTranslation [" + this + "] discarding JavaScriptUnit: " + fCompilationUnit); //$NON-NLS-1$ //$NON-NLS-2$ System.out.println("------------------------------------------------------------------"); //$NON-NLS-1$ } fCompilationUnit.discardWorkingCopy(); } catch (JavaScriptModelException e) { // we're done w/ it anyway } } } } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.web.core.internal.java.IJsTranslation#setProblemCollectingActive(boolean) */ public void setProblemCollectingActive(boolean collect) { IJavaScriptUnit cu = getCompilationUnit(); if (cu != null) { getProblemRequestor().setIsActive(collect); } } public void classpathChange() { if (fDocumentScope != null) { fDocumentScope.classpathChange(); } } }