/*******************************************************************************
* Copyright (c) 2009 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.el.core;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.jboss.tools.common.el.core.model.ELExpression;
import org.jboss.tools.common.el.core.model.ELInstance;
import org.jboss.tools.common.el.core.model.ELModel;
import org.jboss.tools.common.el.core.parser.ELParser;
import org.jboss.tools.common.el.core.parser.ELParserUtil;
import org.jboss.tools.common.el.core.parser.SyntaxError;
import org.jboss.tools.common.text.ITextSourceReference;
import org.jboss.tools.common.util.FileUtil;
import org.jboss.tools.common.util.UniquePaths;
import org.w3c.dom.Element;
/**
* Represents a reference to EL in a resource
* @author Alexey Kazakov
*/
public class ELReference implements ITextSourceReference {
private IPath path;
private int length;
private int lineNumber;
private int startPosition;
private Set<IMarker> markers;
private boolean needToInitMarkers = false;
private String source;
private String elMarkerGroupID;
public ELReference() {
}
public ELReference(String elMarkerGroupID) {
this.elMarkerGroupID = elMarkerGroupID;
}
/**
* @return
*/
public int getLineNumber() {
return lineNumber;
}
/**
* @param lineNumber the lineNumber to set
*/
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
/* (non-Javadoc)
* @see org.jboss.tools.seam.core.ISeamTextSourceReference#getLength()
*/
public int getLength() {
return length;
}
/* (non-Javadoc)
* @see org.jboss.tools.seam.core.ISeamTextSourceReference#getStartPosition()
*/
public int getStartPosition() {
return startPosition;
}
/**
* @param length
*/
public void setLength(int length) {
this.length = length;
}
/**
* @param startPosition
*/
public void setStartPosition(int startPosition) {
this.startPosition = startPosition;
}
/**
* @return the resource
*/
public IFile getResource() {
return ResourcesPlugin.getWorkspace().getRoot().getFile(path);
}
/**
* @param resource the resource to set
*/
public void setResource(IFile resource) {
if(resource != null) {
this.path = UniquePaths.getInstance().intern(resource.getFullPath());
}
}
/**
* @return the path
*/
public IPath getPath() {
return path;
}
/**
* @param path the path to set
*/
public void setPath(IPath path) {
this.path = UniquePaths.getInstance().intern(path);
}
public String getSourceText() {
if(source == null) {
source = getText();// getELModel().getSource();
}
return source;
}
public int getStartPossitionOfFirstEL() {
ELExpression[] els = getEl();
if(els.length>0) {
return startPosition + els[0].getStartPosition();
}
return startPosition;
}
/**
* Helper method, text should be the segment of file content determined by startPosition and length.
* Check is not done, because it would affect performance.
*
* @param text
*/
public ELExpression[] init(String text) {
ELParser parser = ELParserUtil.getJbossFactory().createParser();
ELModel model = parser.parse(text);
return setEl(model.getInstances());
}
/**
* @return the el
*/
public ELExpression[] getEl() {
ELExpression[] el = null;
String text = getSourceText();
if(text.length() > 0) {
el = init(text);
} else {
el = new ELExpression[0];
}
return el;
}
private String getText() {
String text = FileUtil.getContentFromEditorOrFile(getResource());
if(text != null && getStartPosition() >= 0 && getLength() >= 0 && text.length() >= getStartPosition() + getLength()) {
return source = "" + text.substring(getStartPosition(), getStartPosition() + getLength());
} else {
return source = "";
}
}
/**
* @param insts
*/
public ELExpression[] setEl(List<ELInstance> insts) {
Set<ELExpression> exps = new HashSet<ELExpression>();
for (ELInstance el : insts) {
exps.add(el.getExpression());
}
return exps.toArray(new ELExpression[0]);
}
private static final IMarker[] EMPTY_MARKER_ARRAY = new IMarker[0];
private void initMarkers() {
if(markers == null && needToInitMarkers) {
IFile file = getResource();
if(file!=null) {
IMarker[] markers = null;
try {
markers = file.findMarkers(null, true, IResource.DEPTH_INFINITE);
} catch (CoreException e) {
ELCorePlugin.getDefault().logError(e);
}
for(int i=0; i<markers.length; i++){
String groupName = markers[i].getAttribute("groupName", null); //$NON-NLS-1$
if(groupName!=null && (groupName.equals(this.elMarkerGroupID))) {
int start = markers[i].getAttribute(IMarker.CHAR_START, -1);
int end = markers[i].getAttribute(IMarker.CHAR_END, -1);
if(start>=startPosition && end<=startPosition+length) {
addMarker(markers[i]);
}
}
}
}
needToInitMarkers = false;
}
}
/**
* @return the syntaxErrors
*/
public List<SyntaxError> getSyntaxErrors() {
ELParser parser = ELParserUtil.getJbossFactory().createParser();
String text = getSourceText();
if(text.length() == 0) return Collections.emptyList();
ELModel model = parser.parse(text);
return model.getSyntaxErrors();
}
public String getMarkerGroupId() {
return this.elMarkerGroupID;
}
/**
* @param needToInitMarkers the needToInitMarkers to set
*/
public synchronized void setNeedToInitMarkers(boolean needToInitMarkers) {
this.needToInitMarkers = needToInitMarkers;
}
/**
* @param markers the markers to set
*/
public synchronized void addMarker(IMarker marker) {
if(marker==null) {
return;
}
if(markers==null) {
markers = new HashSet<IMarker>();
}
markers.add(marker);
}
/**
* Removes all markers from this EL.
*/
public void deleteMarkers() {
Set<IMarker> aMarkers = null;
synchronized (this) {
initMarkers();
if(markers == null) {
return;
}
aMarkers = markers;
markers = null;
}
for (IMarker marker : aMarkers) {
try {
marker.delete();
} catch (CoreException e) {
ELCorePlugin.getDefault().logError(e);
}
}
}
/**
* Store this EL into XML element.
* @param element
*/
public synchronized void store(Element element, Map<String,String> pathIds) {
element.setAttribute("path", getAlias(pathIds, path.toString())); //$NON-NLS-1$
element.setAttribute("offset", "" + startPosition); //$NON-NLS-1$ //$NON-NLS-2$
element.setAttribute("length", "" + length); //$NON-NLS-1$ //$NON-NLS-2$
}
public static String getAlias(Map<String, String> pathAliases, String path) {
String result = pathAliases.get(path);
if(result == null) {
result = "%" + pathAliases.size(); //$NON-NLS-1$
pathAliases.put(path, result);
}
return result;
}
public static String getPath(Map<String, String> pathAliases, String alias) {
return pathAliases.containsKey(alias) ? pathAliases.get(alias) : alias;
}
/**
* Load this EL from XML element.
* @param element
*/
public synchronized void load(Element element, Map<String, String> pathAliases) {
path = new Path(getPath(pathAliases, element.getAttribute("path"))); //$NON-NLS-1$
setPath(path);
startPosition = new Integer(element.getAttribute("offset")); //$NON-NLS-1$
length = new Integer(element.getAttribute("length")); //$NON-NLS-1$
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
ELReference el = (ELReference)obj;
return this.path.equals(el.path) && this.startPosition == el.startPosition;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return path.hashCode() + startPosition;
}
public ELModel getELModel() {
ELExpression[] exprs = getEl();
if(exprs.length>0) {
return exprs[0].getModel();
}
return null;
}
}