/*******************************************************************************
* Copyright (c) 2006 Zend Corporation and IBM Corporation.
* 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:
* Zend and IBM - Initial implementation
*******************************************************************************/
package org2.eclipse.php.internal.core.project.options;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ProjectScope;
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.SubProgressMonitor;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.osgi.service.prefs.BackingStoreException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org2.eclipse.php.internal.core.CoreMessages;
import org2.eclipse.php.internal.core.project.IIncludePathContainer;
import org2.eclipse.php.internal.core.project.IIncludePathEntry;
import org2.eclipse.php.internal.core.project.options.includepath.IncludePathEntry;
import org2.eclipse.php.internal.core.project.options.includepath.IncludePathVariableManager;
import com.aptana.editor.php.core.IPHPCoreEPLConstants;
import com.aptana.editor.php.core.PHPNature;
import com.aptana.editor.php.epl.PHPEplPlugin;
@SuppressWarnings("restriction")
public class PHPProjectOptions
{
private static final String LOCATION_INCLUDE_PATH = "Include Path"; //$NON-NLS-1$
private static final String OWNER_PHP_INCLUDE_PATH = "phpIncludePath"; //$NON-NLS-1$
private static final String OWNER_ATTRIBUTE = "Owner"; //$NON-NLS-1$
public static final String BUILDER_ID = "com.aptana.editor.php.aptanaPhpBuilder"; //$NON-NLS-1$
static final IIncludePathEntry[] EMPTY_INCLUDEPATH = {};
private static final String PREF_QUALIFIER = PHPEplPlugin.PLUGIN_ID + ".projectOptions"; //$NON-NLS-1$
private static final String OLD_FILE_NAME = ".projectOptions"; //$NON-NLS-1$
private static final String TAG_OPTION = "projectOption"; //$NON-NLS-1$
private static final String TAG_OPTIONS = "phpProjectOptions"; //$NON-NLS-1$
/**
* Name of the User Library Container id.
*/
public static final String USER_LIBRARY_CONTAINER_ID = "org2.eclipse.php.USER_LIBRARY"; //$NON-NLS-1$
public static PHPProjectOptions forProject(final IProject project)
{
if (!project.exists() || !project.isAccessible())
{
return null;
}
PHPNature nature = null;
try
{
nature = (PHPNature) project.getNature(PHPNature.NATURE_ID);
}
catch (final CoreException e)
{
PHPEplPlugin.logError("Unexpected exception", e); //$NON-NLS-1$
}
return (nature != null) ? nature.getOptions() : null;
}
public static IIncludePathContainer getIncludePathContainer(final IPath path, final IProject project2)
{
return null;
}
// public static IncludePathContainerInitializer getIncludePathContainerInitializer(final String string) {
// return null;
// }
public static IPath getIncludePathVariable(final String variableName)
{
return IncludePathVariableManager.instance().getIncludePathVariable(variableName);
}
public static String[] getIncludePathVariableNames()
{
return IncludePathVariableManager.instance().getIncludePathVariableNames();
}
public static IPath getResolvedVariablePath(final IPath path)
{
return IncludePathVariableManager.instance().getIncludePathVariable(path.toString());
}
public static void setIncludePathVariables(final String[] names, final IPath[] paths,
final SubProgressMonitor monitor)
{
IncludePathVariableManager.instance().setIncludePathVariables(names, paths, monitor);
}
private IIncludePathEntry[] includePathEntries = {};
private final Map<String, List<IPhpProjectOptionChangeListener>> optionsChangeListenersMap = new HashMap<String, List<IPhpProjectOptionChangeListener>>();
private IProject project;
private IEclipsePreferences preferences;
public PHPProjectOptions(final IProject project)
{
// assert project != null;
this.project = project;
ProjectScope projectScope = new ProjectScope(project);
preferences = projectScope.getNode(PREF_QUALIFIER);
loadIncludePath();
// backward compatible
loadOldConfiguration();
}
public void addOptionChangeListener(final String optionKey,
final IPhpProjectOptionChangeListener optionChangeListener)
{
List<IPhpProjectOptionChangeListener> optionChangeListeners = optionsChangeListenersMap.get(optionKey);
if (optionChangeListeners == null)
{
optionChangeListeners = new ArrayList<IPhpProjectOptionChangeListener>();
optionsChangeListenersMap.put(optionKey, optionChangeListeners);
}
if (!optionChangeListeners.contains(optionChangeListener))
{
optionChangeListeners.add(optionChangeListener);
}
}
public void removeOptionChangeListener(final String optionKey,
final IPhpProjectOptionChangeListener optionChangeListener)
{
List<IPhpProjectOptionChangeListener> optionChangeListeners = optionsChangeListenersMap.get(optionKey);
if (optionChangeListeners != null)
{
optionChangeListeners.remove(optionChangeListener);
}
}
public void notifyOptionChangeListeners(final String key, final Object oldValue, final Object newValue)
{
List<IPhpProjectOptionChangeListener> optionChangeListeners = optionsChangeListenersMap.get(key);
if (optionChangeListeners == null)
{
return;
}
for (IPhpProjectOptionChangeListener phpProjectOptionChangeListener : optionChangeListeners)
{
phpProjectOptionChangeListener.notifyOptionChanged(oldValue, newValue);
}
}
public IProject getProject()
{
return project;
}
public Object getOption(final String key)
{
return preferences.get(key, null);
}
public void setOption(final String key, final Object value)
{
final Object oldValue = getOption(key);
if (oldValue != null)
{
if (value != null && value.equals(oldValue))
{
return;
}
}
else if (value == null)
{
return;
}
preferences.put(key, value.toString());
flushPrefs();
notifyOptionChangeListeners(key, oldValue, value);
}
public Object removeOption(final String key)
{
final Object object = getOption(key);
if (object != null)
{
preferences.remove(key);
flushPrefs();
}
return object;
}
private void flushPrefs()
{
try
{
preferences.flush();
}
catch (BackingStoreException e)
{
PHPEplPlugin.logError("Unexpected exception", e); //$NON-NLS-1$
}
}
public Object removeOptionNotify(final String key)
{
final Object object = removeOption(key);
notifyOptionChangeListeners(key, object, null);
return object;
}
public void modifyIncludePathEntry(final IIncludePathEntry newEntry, final IProject jproject,
final IPath containerPath, final IProgressMonitor monitor)
{
throw new RuntimeException("implement me"); //$NON-NLS-1$
}
public IIncludePathEntry[] readRawIncludePath()
{
return includePathEntries;
}
public void removeResourceFromIncludePath(final IResource resource)
{
if (includePathEntries.length == 0)
{
return;
}
List<IIncludePathEntry> newIncludePathEntries = new ArrayList<IIncludePathEntry>(includePathEntries.length);
for (IIncludePathEntry entry : includePathEntries)
{
if (entry.getResource() == resource)
{
continue;
}
newIncludePathEntries.add(entry);
}
try
{
setRawIncludePath(newIncludePathEntries.toArray(new IIncludePathEntry[newIncludePathEntries.size()]), null);
return;
}
catch (final Exception e)
{
PHPEplPlugin.logError("Unexpected exception", e); //$NON-NLS-1$
}
}
public void renameResourceAtIncludePath(final IResource from, final IResource to)
{
if (includePathEntries.length == 0)
{
return;
}
List<IIncludePathEntry> newIncludePathEntries = new ArrayList<IIncludePathEntry>(includePathEntries.length);
for (IIncludePathEntry entry : includePathEntries)
{
if (entry.getResource() == from)
{
IIncludePathEntry newSourceEntry = IncludePathEntry.newProjectEntry(to.getFullPath(), to, false);
newIncludePathEntries.add(newSourceEntry);
}
else
{
newIncludePathEntries.add(entry);
}
}
try
{
setRawIncludePath(newIncludePathEntries.toArray(new IIncludePathEntry[newIncludePathEntries.size()]), null);
}
catch (final Exception e)
{
PHPEplPlugin.logError("Unexpected exception", e); //$NON-NLS-1$
}
}
public void setRawIncludePath(final IIncludePathEntry[] newIncludePathEntries,
final SubProgressMonitor subProgressMonitor)
{
final IIncludePathEntry[] oldValue = includePathEntries;
includePathEntries = newIncludePathEntries;
IncludePathEntry.updateProjectReferences(includePathEntries, oldValue, project, subProgressMonitor);
saveIncludePath();
notifyOptionChangeListeners(IPHPCoreEPLConstants.PHPOPTION_INCLUDE_PATH, oldValue, newIncludePathEntries);
}
private void saveIncludePath()
{
try
{
final ByteArrayOutputStream s = new ByteArrayOutputStream();
final XMLWriter xmlWriter = new XMLWriter(s);
xmlWriter.startTag(IncludePathEntry.TAG_INCLUDEPATH, null);
for (IIncludePathEntry entry : includePathEntries)
{
((IncludePathEntry) entry).elementEncode(xmlWriter, project.getFullPath(), true);
}
xmlWriter.endTag(IncludePathEntry.TAG_INCLUDEPATH);
xmlWriter.flush();
xmlWriter.close();
preferences.put(IPHPCoreEPLConstants.PHPOPTION_INCLUDE_PATH, new String(s.toByteArray()));
flushPrefs();
validateIncludePath();
}
catch (IOException e)
{
PHPEplPlugin.logError("Unexpected exception", e); //$NON-NLS-1$
}
finally
{
}
}
private void loadIncludePath()
{
try
{
String includePathXml = preferences.get(IPHPCoreEPLConstants.PHPOPTION_INCLUDE_PATH, null);
if (includePathXml == null)
{
return;
}
Element cpElement;
final Reader reader = new StringReader(includePathXml);
try
{
final DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
}
catch (final Exception e)
{
throw new IOException(CoreMessages.getString("PHPProjectOptions_1")); //$NON-NLS-1$
}
finally
{
reader.close();
}
final List<IIncludePathEntry> paths = new ArrayList<IIncludePathEntry>();
NodeList list = cpElement.getElementsByTagName(IncludePathEntry.TAG_INCLUDEPATHENTRY);
for (int i = 0; i < list.getLength(); ++i)
{
final Node node = list.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
final IIncludePathEntry entry = IncludePathEntry.elementDecode((Element) node, this);
paths.add(entry);
}
}
final int pathSize = paths.size();
includePathEntries = new IIncludePathEntry[pathSize];
paths.toArray(includePathEntries);
}
catch (IOException e)
{
PHPEplPlugin.logError("Unexpected exception", e); //$NON-NLS-1$
}
finally
{
}
}
private void loadOldConfiguration()
{
final IFile optionsFile = project.getFile(OLD_FILE_NAME);
if (!optionsFile.exists())
{
return;
}
List<IIncludePathEntry> paths = new ArrayList<IIncludePathEntry>();
includePathEntries = EMPTY_INCLUDEPATH;
try
{
Element cpElement;
Reader reader = new InputStreamReader(optionsFile.getContents());
try
{
final DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
}
catch (final Exception e)
{
throw new IOException(CoreMessages.getString("PHPProjectOptions_1")); //$NON-NLS-1$
}
finally
{
reader.close();
}
if (!cpElement.getNodeName().equalsIgnoreCase(TAG_OPTIONS))
{
throw new IOException(CoreMessages.getString("PHPProjectOptions_1")); //$NON-NLS-1$
}
NodeList list = cpElement.getElementsByTagName(TAG_OPTION);
int length = list.getLength();
for (int i = 0; i < length; ++i)
{
Element element = (Element) list.item(i);
String key = element.getAttribute("name"); //$NON-NLS-1$
Node firstChild = element.getFirstChild();
if (firstChild != null)
{
String value = firstChild.getNodeValue().trim();
preferences.put(key, value);
}
}
list = cpElement.getElementsByTagName(IncludePathEntry.TAG_INCLUDEPATH);
if (list.getLength() > 0)
{
Element includePathElement = (Element) list.item(0);
list = includePathElement.getElementsByTagName(IncludePathEntry.TAG_INCLUDEPATHENTRY);
length = list.getLength();
for (int i = 0; i < length; ++i)
{
Node node = list.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
IIncludePathEntry entry = IncludePathEntry.elementDecode((Element) node, this);
paths.add(entry);
}
}
int pathSize = paths.size();
includePathEntries = new IIncludePathEntry[pathSize];
paths.toArray(includePathEntries);
}
saveIncludePath();
optionsFile.delete(true, new NullProgressMonitor());
}
catch (IOException e)
{
PHPEplPlugin.logError("Unexpected exception", e); //$NON-NLS-1$
}
catch (CoreException e)
{
PHPEplPlugin.logError("Unexpected exception", e); //$NON-NLS-1$
}
}
public void validateIncludePath()
{
clearMarkers();
for (IIncludePathEntry element : includePathEntries)
{
String message = element.validate();
if (message != null)
{
addError(message);
}
}
}
private void addError(String message)
{
try
{
IMarker marker = project.createMarker(IMarker.PROBLEM);
marker.setAttribute(IMarker.LOCATION, LOCATION_INCLUDE_PATH);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
marker.setAttribute(OWNER_ATTRIBUTE, OWNER_PHP_INCLUDE_PATH);
}
catch (CoreException e)
{
}
}
private void clearMarkers()
{
try
{
IMarker[] markers = project.findMarkers(IMarker.PROBLEM, false, IResource.DEPTH_INFINITE);
for (IMarker element : markers)
{
if (OWNER_PHP_INCLUDE_PATH.equals(element.getAttribute(OWNER_ATTRIBUTE)))
{
element.delete();
}
}
}
catch (CoreException e)
{
}
}
}