/******************************************************************************* * Copyright 2013 Geoscience Australia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package au.gov.ga.earthsci.layer; import gov.nasa.worldwind.layers.AbstractLayer; import gov.nasa.worldwind.render.DrawContext; import java.lang.reflect.Constructor; import java.net.URI; import org.eclipse.core.runtime.Platform; import org.eclipse.e4.core.contexts.IEclipseContext; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import au.gov.ga.earthsci.common.persistence.IPersistentAdapter; import au.gov.ga.earthsci.common.util.Util; import au.gov.ga.earthsci.core.model.IModelStatus; import au.gov.ga.earthsci.core.model.ModelStatus; import au.gov.ga.earthsci.layer.tree.ILayerNode; import au.gov.ga.earthsci.layer.wrappers.ILayerWrapper; /** * {@link IPersistentAdapter} implementation for {@link IPersistentLayer} * instances. Calls the {@link IPersistentLayer#load} and * {@link IPersistentLayer#save} methods to load/save the XML to the persistent * element. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class LayerPersistentAdapter implements IPersistentAdapter<IPersistentLayer> { private static final Logger logger = LoggerFactory.getLogger(LayerPersistentAdapter.class); private final static String ID_ATTRIBUTE = "id"; //$NON-NLS-1$ private final static String BUNDLE_ATTRIBUTE = "bundle"; //$NON-NLS-1$ private final static String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ @Override public void toXML(IPersistentLayer layer, Element element, URI context) { String id, bundleName, className; if (layer instanceof MissingLayer) { MissingLayer missing = (MissingLayer) layer; id = missing.id; bundleName = missing.bundleName; className = missing.className; } else { id = ExtensionManager.getInstance().getIdForLayerOrWrapper(layer); bundleName = FrameworkUtil.getBundle(layer.getClass()).getSymbolicName(); className = layer.getClass().getName(); } if (!Util.isEmpty(id)) { element.setAttribute(ID_ATTRIBUTE, id); } else if (!Util.isEmpty(bundleName) && !Util.isEmpty(className)) { element.setAttribute(BUNDLE_ATTRIBUTE, bundleName); element.setAttribute(CLASS_ATTRIBUTE, className); } layer.save(element); } @Override public IPersistentLayer fromXML(Element element, URI context) { String id = element.getAttribute(ID_ATTRIBUTE); String className = element.getAttribute(CLASS_ATTRIBUTE); String bundleName = element.getAttribute(BUNDLE_ATTRIBUTE); try { Class<? extends IPersistentLayer> c; if (!Util.isEmpty(id)) { String replacement = ExtensionManager.getInstance().getReplacementIdFor(id); if (!Util.isEmpty(replacement)) { id = replacement; } c = ExtensionManager.getInstance().getLayerOrWrapperForId(id); if (c == null) { throw new IllegalArgumentException("Layer or wrapper class not found for id '" + id + "'"); //$NON-NLS-1$ //$NON-NLS-2$ } } else if (!Util.isEmpty(className)) { c = ExtensionManager.getInstance().getReplacementClassFor(className); if (c == null) { Bundle bundle = Platform.getBundle(bundleName); @SuppressWarnings({ "unchecked" }) Class<? extends IPersistentLayer> cl = (Class<? extends IPersistentLayer>) bundle.loadClass(className); c = cl; } } else { throw new IllegalArgumentException("No layer id or class specified"); //$NON-NLS-1$ } Constructor<? extends IPersistentLayer> constructor = c.getDeclaredConstructor(); constructor.setAccessible(true); IPersistentLayer layer = constructor.newInstance(); layer.load(element); //check if a wrapped layer should actually be wrapped by a different wrapper if (layer instanceof ILayerWrapper) { ILayerWrapper wrapper = (ILayerWrapper) layer; ILayerWrapper otherWrapper = ExtensionManager.getInstance().wrapLayer(wrapper.getLayer()); if (!otherWrapper.getClass().isAssignableFrom(wrapper.getClass())) { layer = otherWrapper; } } return layer; } catch (Exception e) { logger.error("Error creating Layer from XML", e); //$NON-NLS-1$ return new MissingLayer(id, bundleName, className, element); } } /** * Basic {@link IPersistentLayer} implementation used for storage of the * layer XML when the layer class cannot be found. */ private static class MissingLayer extends AbstractLayer implements IPersistentLayer { private final String id; private final String bundleName; private final String className; private final Element parent; private IModelStatus status; public MissingLayer(String id, String bundleName, String className, Element parent) { this.id = id; this.bundleName = bundleName; this.className = className; this.parent = parent; String message = !Util.isEmpty(id) ? "Layer not found with id: " + id : "Layer class not found: " + className; //$NON-NLS-1$ //$NON-NLS-2$ this.status = ModelStatus.error(message, null); } @Override public void load(Element parent) { } @Override public void save(Element parent) { NodeList children = this.parent.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); Node imported = parent.getOwnerDocument().importNode(child, true); parent.appendChild(imported); } NamedNodeMap attributes = this.parent.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); parent.setAttribute(attribute.getNodeName(), attribute.getNodeValue()); } } @Override public void initialize(ILayerNode node, IEclipseContext context) { } @Override public boolean isLoading() { return false; } @Override protected void doRender(DrawContext dc) { } @Override public String getName() { return status.getMessage(); } } }