/*
* JBoss by Red Hat
* Copyright 2006-2009, Red Hat Middleware, LLC, and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ide.eclipse.freemarker.configuration;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
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.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JarEntryFile;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.swt.widgets.Shell;
import org.jboss.ide.eclipse.freemarker.Messages;
import org.jboss.ide.eclipse.freemarker.Plugin;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
*/
public class ConfigurationManager {
private static final Map instances = new HashMap();
private IProject project;
private ProjectClassLoader projectClassLoader;
private Map contextValues = new HashMap();
private Map macroLibrary = new HashMap();
private MacroLibrary[] macroLibraryArr;
private ConfigurationManager () {}
public synchronized static final ConfigurationManager getInstance (IProject project) {
ConfigurationManager configuration =
(ConfigurationManager) instances.get(project.getName());
if (null == configuration) {
configuration = new ConfigurationManager();
configuration.project = project;
configuration.reload();
instances.put(project.getName(), configuration);
}
return configuration;
}
public MacroLibrary[] getMacroLibraries () {
return macroLibraryArr;
}
public void associateMappingLibraries (List libraries, Shell shell) {
for (Iterator i=libraries.iterator(); i.hasNext(); ) {
Object obj = i.next();
if (obj instanceof IFile) {
IFile file = (IFile) obj;
String namespace = file.getName();
int index = namespace.indexOf("."); //$NON-NLS-1$
if (index >= 0) namespace = namespace.substring(0, index);
InputDialog inputDialog = new InputDialog(
shell, Messages.ConfigurationManager_TITLE_CHOOSE_NAMESPACE,
MessageFormat.format(
Messages.ConfigurationManager_CHOOSE_NAMESPACE_FOR, file
.getName()),
namespace, null);
int rtn = inputDialog.open();
if (rtn == IDialogConstants.OK_ID) {
namespace = inputDialog.getValue();
try {
this.macroLibrary.put(namespace, new MacroLibrary(namespace, file));
}
catch (CoreException e) {
Plugin.error(e);
}
catch (IOException e) {
Plugin.error(e);
}
}
}
else if (obj instanceof JarEntryFile) {
JarEntryFile jef = (JarEntryFile) obj;
String namespace = jef.getName();
int index = namespace.indexOf("."); //$NON-NLS-1$
if (index >= 0) namespace = namespace.substring(0, index);
InputDialog inputDialog = new InputDialog(
shell, Messages.ConfigurationManager_TITLE_CHOOSE_NAMESPACE,
MessageFormat.format(
Messages.ConfigurationManager_CHOOSE_NAMESPACE_FOR, jef
.getName()),
namespace, null);
int rtn = inputDialog.open();
if (rtn == IDialogConstants.OK_ID) {
namespace = inputDialog.getValue();
try {
InputStream is = getProjectClassLoader().getResourceAsStream(jef.getFullPath().toString());
if (null != is) {
this.macroLibrary.put(namespace, new MacroLibrary(namespace, is, jef.getFullPath().toString(), MacroLibrary.TYPE_JAR_ENTRY));
}
else {
// FIXME: add error dialog here
}
}
catch (CoreException e) {
Plugin.error(e);
}
catch (IOException e) {
Plugin.error(e);
}
}
}
}
save();
}
public MacroLibrary getMacroLibrary (String namespace) {
return (MacroLibrary) macroLibrary.get(namespace);
}
private void writeMacroLibrary(StringBuffer sb) {
for (Iterator i=macroLibrary.values().iterator(); i.hasNext(); ) {
MacroLibrary macroLibrary = (MacroLibrary) i.next();
sb.append("\t\t" + macroLibrary.toXML() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
private Map loadMacroTemplates (Element element) {
Map map = new HashMap();
try {
NodeList nl = element
.getElementsByTagName("entry"); //$NON-NLS-1$
for (int i = 0; i < nl.getLength(); i++) {
try {
Node n = nl.item(i);
MacroLibrary macroLibrary = MacroLibrary.fromXML(project, (Element) n, getProjectClassLoader());
if (null != macroLibrary) {
map.put(macroLibrary.getNamespace(), macroLibrary);
}
} catch (Exception e) {
Plugin.log(e);
}
}
}
catch (Exception e) {
Plugin.log(e);
}
return map;
}
private IFile getFile (String path) {
return project.getFile(path);
}
private String getPath (IFile file) {
return file.getProjectRelativePath().toString();
}
private Map loadContextValues (Element element) {
Map map = new HashMap();
try {
NodeList nl = element
.getElementsByTagName("resource"); //$NON-NLS-1$
for (int i = 0; i < nl.getLength(); i++) {
try {
Node n = nl.item(i);
String path = ((Element) n).getAttribute("path"); //$NON-NLS-1$
List contextValues = new ArrayList();
NodeList nl2 = ((Element) n)
.getElementsByTagName("value"); //$NON-NLS-1$
for (int j = 0; j < nl2.getLength(); j++) {
Node n2 = nl2.item(j);
String key = ((Element) n2).getAttribute("key"); //$NON-NLS-1$
Class value = getClass(((Element) n2)
.getAttribute("object-class")); //$NON-NLS-1$
String singularName = ((Element) n2)
.getAttribute("item-class"); //$NON-NLS-1$
Class singularClass = null;
if (null != singularName && singularName.trim().length()>0)
singularClass = getClass(singularName);
contextValues.add(new ContextValue(key, value,
singularClass));
}
map.put(path,
contextValues
.toArray(new ContextValue[contextValues
.size()]));
} catch (Exception e) {
Plugin.log(e);
}
}
}
catch (Exception e) {
Plugin.log(e);
}
return map;
}
public synchronized Class getClass(String className)
throws JavaModelException, ClassNotFoundException {
return getProjectClassLoader().loadClass(className);
}
public synchronized ClassLoader getProjectClassLoader() throws JavaModelException {
if (null == this.projectClassLoader)
this.projectClassLoader = new ProjectClassLoader(JavaCore.create(project));
return this.projectClassLoader;
}
private void save() {
StringBuffer sb = new StringBuffer();
sb.append("<config>\n"); //$NON-NLS-1$
sb.append("\t<context-values>\n"); //$NON-NLS-1$
writeContextValues(sb);
sb.append("\t</context-values>\n"); //$NON-NLS-1$
sb.append("\t<macro-library>\n"); //$NON-NLS-1$
writeMacroLibrary(sb);
sb.append("\t</macro-library>\n"); //$NON-NLS-1$
sb.append("</config>"); //$NON-NLS-1$
IFile file = project.getFile(".freemarker-ide.xml"); //$NON-NLS-1$
try {
if (file.exists())
file.setContents(new ByteArrayInputStream(sb.toString()
.getBytes()), true, true, null);
else
file.create(new ByteArrayInputStream(sb.toString().getBytes()),
true, null);
} catch (Exception e) {
Plugin.error(e);
}
reload();
}
public void reload() {
this.projectClassLoader = null;
IFile file = project.getFile(".freemarker-ide.xml"); //$NON-NLS-1$
if (file.exists()) {
try { file.refreshLocal(1, null); } catch (CoreException e) {}
Map map = new HashMap();
try {
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(file.getContents());
NodeList nl = document.getDocumentElement()
.getElementsByTagName("context-values"); //$NON-NLS-1$
if (nl.getLength() > 0)
this.contextValues = loadContextValues((Element) nl.item(0));
else
this.contextValues = new HashMap();
nl = document.getDocumentElement()
.getElementsByTagName(
"macro-library"); //$NON-NLS-1$
List libraries = new ArrayList();
if (nl.getLength() > 0) {
this.macroLibrary = loadMacroTemplates((Element) nl.item(0));
for (Iterator i=macroLibrary.values().iterator(); i.hasNext(); ) {
libraries.add(i.next());
}
}
else
this.macroLibrary = new HashMap();
macroLibraryArr = (MacroLibrary[]) libraries.toArray(new MacroLibrary[libraries.size()]);
} catch (Exception e) {
Plugin.error(e);
}
}
}
private void writeContextValues(StringBuffer sb) {
for (Iterator i = contextValues.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
String fileName = (String) entry.getKey();
ContextValue[] values = (ContextValue[]) entry.getValue();
if (null != values && values.length > 0) {
sb.append("\t\t<resource path=\"" + fileName + "\">\n"); //$NON-NLS-1$//$NON-NLS-2$
for (int j = 0; j < values.length; j++) {
sb
.append("\t\t\t<value key=\"" + values[j].name //$NON-NLS-1$
+ "\" object-class=\"" + values[j].objClass.getName() //$NON-NLS-1$
+ "\""); //$NON-NLS-1$
if (null != values[j].singularClass)
sb.append(" item-class=\"" //$NON-NLS-1$
+ values[j].singularClass.getName() + "\""); //$NON-NLS-1$
sb.append("/>\n"); //$NON-NLS-1$
}
sb.append("\t\t</resource>\n"); //$NON-NLS-1$
}
}
}
public ContextValue[] getContextValues(IResource resource, boolean recurse) {
Map newValues = new HashMap();
addRootContextValues(resource, newValues, recurse);
return (ContextValue[]) newValues.values().toArray(new ContextValue[newValues.size()]);
}
private void addRootContextValues(IResource resource, Map newValues, boolean recurse) {
String key = null;
if (null != resource.getParent()) {
key = resource.getProjectRelativePath().toString();
if (recurse) addRootContextValues(resource.getParent(), newValues, true);
}
else
key = ""; //$NON-NLS-1$
if (null != resource.getProject()) {
ContextValue[] values = (ContextValue[]) contextValues.get(key);
if (null != values) {
for (int i=0; i<values.length; i++) {
newValues.put(values[i].name, values[i]);
}
}
}
}
public ContextValue getContextValue(String name, IResource resource, boolean recurse) {
ContextValue[] values = getContextValues(resource, recurse);
for (int i = 0; i < values.length; i++) {
if (values[i].name.equals(name))
return values[i];
}
return null;
}
public void addContextValue(ContextValue contextValue, IResource resource) {
ContextValue[] contextValues = getContextValues(resource, false);
boolean found = false;
for (int i = 0; i < contextValues.length; i++) {
if (contextValues[i].name.equals(contextValue.name)) {
found = true;
contextValues[i] = contextValue;
this.contextValues.put(
resource.getProjectRelativePath().toString(),
contextValues);
break;
}
}
if (!found) {
ContextValue[] newContextValues = new ContextValue[contextValues.length + 1];
int index = 0;
while (index < contextValues.length) {
newContextValues[index] = contextValues[index++];
}
newContextValues[index] = contextValue;
this.contextValues.put(resource.getProjectRelativePath().toString(), newContextValues);
}
save();
}
public void updateContextValue(ContextValue contextValue, IFile file) {
addContextValue(contextValue, file);
}
public void removeContextValue(String name, IResource resource) {
ContextValue[] values = getContextValues(resource, false);
int index = -1;
for (int i = 0; i < values.length; i++) {
if (values[i].name.equals(name)) {
index = i;
break;
}
}
if (index >= 0) {
ContextValue[] newValues = new ContextValue[values.length - 1];
int j = 0;
for (int i = 0; i < values.length; i++) {
if (i != index)
newValues[j++] = values[i];
}
this.contextValues.put(resource.getProjectRelativePath().toString(), newValues);
save();
}
}
}