/* * ----------------------------------------------------------------------- * File: $HeadURL$ * Revision $LastChangedRevision$ * Last Modified: $LastChangedDate$ * Last Change by: $LastChangedBy$ * ----------------------------------------------------------------------- * Copyright (C) 2007 Keith Stribley <devel@thanlwinsoft.org> * * This library 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 library 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * ----------------------------------------------------------------------- */ /** * */ package org.thanlwinsoft.languagetest.eclipse.workspace; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.ui.PlatformUI; import org.thanlwinsoft.languagetest.eclipse.LanguageTestPlugin; import org.thanlwinsoft.languagetest.language.test.meta.MetaNode; import org.thanlwinsoft.schemas.languagetest.module.ConfigType; import org.thanlwinsoft.schemas.languagetest.module.LanguageModuleDocument; import org.thanlwinsoft.schemas.languagetest.module.MetaDataType; /** * @author keith * */ public class MetaDataManager { public final static String DEFAULT_LANG_CONFIG = "/org/thanlwinsoft/languagetest/language/text/DefaultLangConfig.xml"; public MetaDataManager() {} public static ConfigType [] loadConfig() { Map <ConfigType, ConfigDetails> map = loadConfigFromProjects(); return map.keySet().toArray(new ConfigType[map.size()]); } protected static Map <ConfigType, ConfigDetails> loadConfigFromProjects() { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IProject [] projects = workspace.getRoot().getProjects(); Map <ConfigType, ConfigDetails> config = new HashMap<ConfigType, ConfigDetails>(); for (IProject p : projects) { if (!p.isOpen()) continue; IFile file = p.getFile(WorkspaceLanguageManager.LANG_FILE); LanguageModuleDocument doc; try { doc = LanguageModuleDocument.Factory.parse(file.getContents(), getXmlOptions()); if (doc == null || doc.getLanguageModule() == null || doc.getLanguageModule().isSetConfig() == false) continue; ConfigType c = doc.getLanguageModule().getConfig(); if (c != null) { ConfigDetails cd = new MetaDataManager().new ConfigDetails(file, doc); config.put(c, cd); } } catch (XmlException e) { LanguageTestPlugin.log(IStatus.WARNING, "XML Error loading MetaData config", e); } catch (IOException e) { LanguageTestPlugin.log(IStatus.WARNING, "IO Error loading MetaData config", e); } catch (CoreException e) { LanguageTestPlugin.log(IStatus.WARNING, "Core Error loading MetaData config", e); } } try { InputStream is = LanguageTestPlugin.getDefault().getBundle() .getResource(DEFAULT_LANG_CONFIG).openStream(); XmlOptions options = getXmlOptions(); LanguageModuleDocument langDoc = LanguageModuleDocument.Factory.parse(is, options); if (langDoc != null && langDoc.getLanguageModule() != null && langDoc.getLanguageModule().isSetConfig()) { ConfigType c = langDoc.getLanguageModule().getConfig(); ConfigDetails cd = new MetaDataManager().new ConfigDetails(null, langDoc); config.put(c, cd); } } catch (IOException e) { LanguageTestPlugin.log(IStatus.WARNING, "IO Error loading MetaData config", e); } catch (XmlException e) { LanguageTestPlugin.log(IStatus.WARNING, "XML Error loading MetaData config", e); } return config; } /** * Try to save the node to the most appropriate Project. * If the top level node already exists in one of the projects save it * there. Otherwise, try the Project of the current selection, then the user * project finally the first available open project. * @param node */ public static boolean saveNode(MetaNode node) { Map <ConfigType, ConfigDetails> map = loadConfigFromProjects(); IPath nodePath = node.toPath(); if (nodePath.segmentCount() == 0) { LanguageTestPlugin.log(IStatus.INFO, "MetaNode has no segments to save."); return false; } String seg = node.toPath().segment(0); for (ConfigType c : map.keySet()) { for (MetaDataType md : c.getMetaDataArray()) { if (md.getMetaId().equals(seg)) { ConfigDetails cd = map.get(c); if (cd.file != null) { IProject project = cd.file.getProject(); if (project.isAccessible()) { return saveNodeToProject(node, project); } } } } } // try to find the active project and save it to that IProject p = getActiveProject(); if (p == null) { p = WorkspaceLanguageManager.getUserProject(); } if (p == null) { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IProject [] projects = workspace.getRoot().getProjects(); // finally try to find any open projects for (IProject pTest : projects) { if (pTest.isOpen()) { p = pTest; continue; } } } if (p == null) { LanguageTestPlugin.log(IStatus.WARNING, "Unable to save MetaNode because no project was found"); return false; } return saveNodeToProject(node, p); } private static boolean saveNodeToProject(MetaNode node, IProject project) { boolean success = false; try { final IFile configResource = project.getFile(WorkspaceLanguageManager.LANG_FILE); InputStream is = configResource.getContents(); final XmlOptions options = getXmlOptions(); final LanguageModuleDocument langDoc = LanguageModuleDocument.Factory.parse(is); if (langDoc != null && langDoc.getLanguageModule() != null) { ConfigType c = null; if (langDoc.getLanguageModule().isSetConfig()) c = langDoc.getLanguageModule().getConfig(); else c = langDoc.getLanguageModule().addNewConfig(); IPath nodePath = node.toPath(); MetaDataType levelData = null; for (MetaDataType md : c.getMetaDataArray()) { if (md.getMetaId().equals(nodePath.segment(0))) { levelData = md; break; } } if (levelData == null) { levelData = c.addNewMetaData(); levelData.setMetaId(nodePath.segment(0)); } if (nodePath.segmentCount() == 1) { levelData.set(node.getData()); } MetaDataType prevData = levelData; levelData = null; for (int i = 1; i < nodePath.segmentCount(); i++) { for (MetaDataType md : prevData.getMetaDataArray()) { if (md.getMetaId().equals(nodePath.segment(i))) { levelData = md; break; } } if (levelData == null) { levelData = prevData.addNewMetaData(); levelData.setMetaId(nodePath.segment(i)); } if (nodePath.segmentCount() == i + 1) { levelData.set(node.getData()); } prevData = levelData; levelData = null; } PlatformUI.getWorkbench().getProgressService().run(false, false, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { InputStream is = langDoc.newInputStream(options); if (configResource.exists()) configResource.setContents(is, IFile.NONE, monitor); else configResource.create(is, IFile.NONE, monitor); configResource.refreshLocal(1, monitor); } catch (CoreException e) { LanguageTestPlugin.log(IStatus.ERROR, "Core Error saving MetaNode", e); } } }); success = true; } } catch (XmlException e) { LanguageTestPlugin.log(IStatus.ERROR, "XML Error before saving MetaNode", e); } catch (IOException e) { LanguageTestPlugin.log(IStatus.ERROR, "IO Error saving MetaNode", e); } catch (CoreException e) { LanguageTestPlugin.log(IStatus.ERROR, "Core Error before saving MetaNode", e); } catch (InvocationTargetException e) { LanguageTestPlugin.log(IStatus.ERROR, "Invocation Error saving MetaNode", e); } catch (InterruptedException e) { LanguageTestPlugin.log(IStatus.ERROR, "Interrupted while saving MetaNode", e); } return success; } private static IProject getActiveProject() { IProject p = null; ISelection s = PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getActivePage().getSelection(); if (s instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection)s; if (ss.getFirstElement() instanceof IResource) { p = ((IResource)ss.getFirstElement()).getProject(); } } return p; } /** * Examine the different Config elements to try to find the given metanode * @param mn * @return */ private static MetaDetails findExistingMetaData(MetaNode mn) { MetaDetails details = null; IPath path = mn.toPath(); if (path.segmentCount() == 0) return null; Map <ConfigType, ConfigDetails> map = loadConfigFromProjects(); int leafIndex = 0; int depth = -1; for (ConfigType c : map.keySet()) { depth = -1; leafIndex = 0; for (MetaDataType mdTop : c.getMetaDataArray()) { if (mdTop.getMetaId().equals(path.segment(0))) { depth = 0; MetaDataType prev = mdTop; boolean found = true; for (int i = 1; found && i < path.segmentCount(); i++) { found = false; leafIndex = 0; for (MetaDataType md : prev.getMetaDataArray()) { if (md.getMetaId().equals(path.segment(i))) { if (i + 1 != path.segmentCount()) prev = md; found = true; depth = i; break; } leafIndex++; } } ConfigDetails cd = map.get(c); if (found) { // TODO consider how to handle duplicates better // we can't modify it if it is hard coded if (cd.file != null) { if (details != null) { LanguageTestPlugin.log(IStatus.INFO, "Duplicate Tag " + path.toPortableString() + " " + details.file.getProject().getName() + " & " + cd.file.getProject().getName()); } } details = new MetaDataManager().new MetaDetails(cd.file, cd.doc, depth, prev, leafIndex); } else if (depth > -1 && (details == null || details.depth < depth)) { details = new MetaDataManager().new MetaDetails(cd.file, cd.doc, depth, prev, leafIndex); } break; } leafIndex++; } } return details; } private static XmlOptions getXmlOptions() { final XmlOptions options = new XmlOptions(); options.setCharacterEncoding("UTF-8"); options.setLoadUseDefaultResolver(); options.setSavePrettyPrint(); options.setDocumentType(LanguageModuleDocument.type); return options; } /** * @param mn */ public static boolean deleteNode(MetaNode mn) { final MetaDetails details = findExistingMetaData(mn); boolean success = false; if (details != null) { // check that the MetaNode was found down to the correct depth if (details.depth + 1 < mn.toPath().segmentCount()) { LanguageTestPlugin.log(IStatus.INFO, "Could not find " + mn.getPath() + " to delete or it may be read only."); return false; } if (details.parentData == null) { details.doc.getLanguageModule().getConfig().removeMetaData(details.leafIndex); } else { details.parentData.removeMetaData(details.leafIndex); } final InputStream is = details.doc.newInputStream(getXmlOptions()); try { PlatformUI.getWorkbench().getProgressService().run(false, false, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { details.file.setContents(is, IFile.NONE, monitor); details.file.refreshLocal(1, monitor); } catch (CoreException e) { LanguageTestPlugin.log(IStatus.ERROR, "Error deleting MetaNode", e); } } }); success = true; } catch (InvocationTargetException e) { LanguageTestPlugin.log(IStatus.ERROR, "Invocation Error deleting MetaNode", e); } catch (InterruptedException e) { LanguageTestPlugin.log(IStatus.ERROR, "Interrupted deleting MetaNode", e); } } return success; } /** * Structure to hold the results from findExistingMetaData() * @author keith * */ private class MetaDetails { final IFile file; final LanguageModuleDocument doc; final int depth; final MetaDataType parentData; final int leafIndex; public MetaDetails(IFile file, LanguageModuleDocument doc, int depth, MetaDataType parentData, int leafIndex) { this.file = file; this.doc = doc; this.depth = depth; this.parentData = parentData; this.leafIndex = leafIndex; } } /** * Structure to hold the results from loadConfigFromProject() * @author keith * */ protected class ConfigDetails { final IFile file; final LanguageModuleDocument doc; public ConfigDetails(IFile file, LanguageModuleDocument doc) { this.file = file; this.doc = doc; } } }