/*******************************************************************************
* Copyright (c) 2011 Grupo de Sistemas Inteligentes (GSI) - DIT UPM
*
* 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
*******************************************************************************/
package es.upm.dit.gsi.eclipse.jadex.navigator;
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.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.ui.progress.UIJob;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Class that provides the needed objects to represent the tree of the components
* of an agent file
*
* @author Pablo Muñoz
* @TODO review the updateModel method
*
*/
public class AgentContentProvider implements ITreeContentProvider,
IResourceChangeListener, IResourceDeltaVisitor {
private static final Object[] NO_CHILDREN = new Object[0];
private static final String AGENT_EXT = "agent.xml"; //$NON-NLS-1$
private final Map<IFile, Child[]> cachedModelMap = new HashMap<IFile,Child[]>();
private static final Child[] CATEGORIES = {
new Child("imports", NO_CHILDREN, null), //$NON-NLS-1$
new Child("capabilities",NO_CHILDREN,null), //$NON-NLS-1$
new Child("beliefs",NO_CHILDREN,null), //$NON-NLS-1$
new Child("plans",NO_CHILDREN, null), //$NON-NLS-1$
new Child("goals",NO_CHILDREN, null), //$NON-NLS-1$
new Child("events",NO_CHILDREN, null), //$NON-NLS-1$
new Child("expressions", NO_CHILDREN, null), //$NON-NLS-1$
new Child("properties",NO_CHILDREN,null), //$NON-NLS-1$
new Child("configurations", NO_CHILDREN, null)};
private StructuredViewer viewer;
public AgentContentProvider() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
}
/**
* Return the model elements for a *.agent.xml IFile or
* NO_CHILDREN for otherwise.
*/
public Object[] getChildren(Object parentElement) {
Object[] children = null;
if(parentElement instanceof IFile){
IFile file = (IFile) parentElement;
updateModel(file);
children = cachedModelMap.get(file);
}
else if (parentElement instanceof Child){
Child category = (Child) parentElement;
children = category.getValues();
}
return children != null ? children : NO_CHILDREN;
}
/**
* Load the model from the given file, if possible.
* @param modelFile The IFile which contains the persisted model
*/
private synchronized Object[] updateModel(IFile file) {
if(file.getName().endsWith(AGENT_EXT)){
List<Child> children = new ArrayList<Child>();
if (file.exists()) {
for(Child c : CATEGORIES){
Child nc = new Child(c.getName(), null, file);
Object[] obj = readXML(file, nc);
nc.setValues(obj);
children.add(nc);
/*
Object[] obj = readXML(file, c);
children.add(new Child(c.getName(), obj, file));*/
}
Child[] result = children.toArray(new Child[children.size()]);
cachedModelMap.put(file, result);
return children.toArray();
} else {
cachedModelMap.remove(file);
}
}
return null;
}
public Object getParent(Object element) {
if (element instanceof Child) {
Child data = (Child) element;
return data.getFile();
}
else if (element instanceof SubChild){
SubChild property = (SubChild) element;
return property.getContainer();
}
return null;
}
public boolean hasChildren(Object element) {
if (element instanceof Child) {
Child c = (Child) element;
return (c.getValues().length > 0);
}
else if(element instanceof IFile) {
return ((IFile) element).getName().endsWith(AGENT_EXT);
}
return false;
}
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
public void dispose() {
cachedModelMap.clear();
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
}
public void inputChanged(Viewer aViewer, Object oldInput, Object newInput) {
if (oldInput != null && !oldInput.equals(newInput))
cachedModelMap.clear();
viewer = (StructuredViewer) aViewer;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
*/
public void resourceChanged(IResourceChangeEvent event) {
IResourceDelta delta = event.getDelta();
try {
delta.accept(this);
} catch (CoreException e) {
e.printStackTrace();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
*/
public boolean visit(IResourceDelta delta) {
IResource source = delta.getResource();
switch (source.getType()) {
case IResource.ROOT:
case IResource.PROJECT:
case IResource.FOLDER:
return true;
case IResource.FILE:
final IFile file = (IFile) source;
if (file.getName().endsWith(AGENT_EXT)) {
updateModel(file);
new UIJob("Update Properties Model in CommonViewer") { //$NON-NLS-1$
public IStatus runInUIThread(IProgressMonitor monitor) {
if (viewer != null && !viewer.getControl().isDisposed())
viewer.refresh(file);
return Status.OK_STATUS;
}
}.schedule();
}
return false;
}
return false;
}
private static Object[] readXML(IFile inputFile, Child parent){
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance ( );
Document document = null;
List<SubChild> nodes = new ArrayList<SubChild>();
try
{
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(inputFile.getRawLocationURI().getRawPath());
Node node = document.getElementsByTagName(parent.getName()).item(0);
NodeList nodeList = node.getChildNodes();
for(int i=0; i < nodeList.getLength(); i++){
String nodeName = nodeList.item(i).getNodeName();
if(!nodeName.equals("#comment") && !nodeName.equals("#text")){ //$NON-NLS-1$ //$NON-NLS-2$
Element element = (Element) nodeList.item(i);
String type = element.getNodeName();
String name = element.getAttribute("name");
if(type.equals("plan")){
Element body = (Element) element.getElementsByTagName("body").item(0);
String _class = body.getAttribute("class");
nodes.add(new SubChild(parent, name, _class, type ));
}
else if (type.equals("capability")){
nodes.add(new SubChild(parent, name, element.getAttribute("file"), type));
}
else{
nodes.add(new SubChild(parent, type, name, type));
}
}
}
return nodes.toArray();
}
catch (Exception spe)
{
// Algún tipo de error: fichero no accesible, formato de XML incorrecto, etc.
}
return null;
}
}