/******************************************************************************* * 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.catalog; import java.net.URI; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Shell; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import au.gov.ga.earthsci.common.util.UTF8URLEncoder; import au.gov.ga.earthsci.intent.AbstractIntentCallback; import au.gov.ga.earthsci.intent.IIntentCallback; import au.gov.ga.earthsci.intent.Intent; import au.gov.ga.earthsci.intent.IntentManager; import au.gov.ga.earthsci.intent.dispatch.DispatchFilter; import au.gov.ga.earthsci.intent.dispatch.Dispatcher; import au.gov.ga.earthsci.notification.NotificationCategory; import au.gov.ga.earthsci.notification.NotificationManager; /** * Catalog loading helper which uses the Intent system for loading catalogs from * files/URIs. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class IntentCatalogLoader { private static final Object replaceNodeSemaphore = new Object(); private final static Logger logger = LoggerFactory.getLogger(IntentCatalogLoader.class); public static void load(URI uri, ICatalogTreeNode placeholder, IEclipseContext context) { load(uri, null, placeholder, context); } public static void load(URI uri, IContentType contentType, ICatalogTreeNode placeholder, IEclipseContext context) { CatalogLoadIntent intent = new CatalogLoadIntent(placeholder, context); intent.setURI(uri); intent.setContentType(contentType); intent.setExpectedReturnType(ICatalogTreeNode.class); IntentManager.getInstance().start(intent, callback, context); } protected static IIntentCallback callback = new AbstractIntentCallback() { @Override public void completed(final Object result, Intent intent) { final CatalogLoadIntent catalogIntent = (CatalogLoadIntent) intent; if (result instanceof ICatalogTreeNode) { ICatalogTreeNode node = (ICatalogTreeNode) result; replaceWithNode(catalogIntent, node); } else { final DispatchFilter filter = Dispatcher.getInstance().findFilter(result); if (filter != null) { final Shell shell = catalogIntent.context.get(Shell.class); shell.getDisplay().asyncExec(new Runnable() { @Override public void run() { MessageDialog dialog = new MessageDialog(shell, Messages.IntentCatalogLoader_UnknownCatalogDialogTitle, null, Messages.bind(Messages.IntentCatalogLoader_UnknownCatalogDialogMessage, filter.getName()), MessageDialog.QUESTION, new String[] { Messages.IntentCatalogLoader_UnknownCatalogDialogYes, Messages.IntentCatalogLoader_UnknownCatalogDialogNo }, 0); if (dialog.open() == 0) { replaceWithNode(catalogIntent, null); Dispatcher.getInstance().dispatch(result, catalogIntent, catalogIntent.context); } } }); } else { error(new Exception( Messages.bind(Messages.IntentCatalogLoader_UnknownResultMessage, ICatalogTreeNode.class.getSimpleName(), result.getClass().getSimpleName())), intent); } } } @Override public void error(Exception e, Intent intent) { //TODO cannot let this notification require acknowledgement during initial loading (catalog unpersistence) //as it causes the parts to be created incorrectly (bad parent window perhaps?) String title = Messages.bind(Messages.IntentCatalogLoader_FailedToLoadCatalogTitle, UTF8URLEncoder.decode(intent.getURI().toString())); String message = Messages.bind(Messages.IntentCatalogLoader_FailedToLoadCatalogMessage, UTF8URLEncoder.decode(intent.getURI().toString()), e.getLocalizedMessage()); NotificationManager.error(title, message, NotificationCategory.FILE_IO, e); logger.error(message, e); CatalogLoadIntent catalogIntent = (CatalogLoadIntent) intent; ErrorCatalogTreeNode errorNode = new ErrorCatalogTreeNode(intent.getURI(), title, e); errorNode.setRemoveable(true); replaceWithNode(catalogIntent, errorNode); } @Override public void canceled(Intent intent) { CatalogLoadIntent catalogIntent = (CatalogLoadIntent) intent; ErrorCatalogTreeNode errorNode = new ErrorCatalogTreeNode( intent.getURI(), new Exception(Messages.IntentCatalogLoader_CatalogLoadCanceledMessage)); errorNode.setRemoveable(true); replaceWithNode(catalogIntent, errorNode); } @Override public void aborted(Intent intent) { replaceWithNode((CatalogLoadIntent) intent, null); } private void replaceWithNode(CatalogLoadIntent intent, ICatalogTreeNode node) { //only allow one node to be replaced at a time; synchronize on a static object: synchronized (replaceNodeSemaphore) { ICatalogTreeNode placeholder = intent.replacement != null ? intent.replacement : intent.placeholder; if (placeholder.getParent() == null) { //If placeholder parent is null, probably means the placeholder has been removed from //the tree by the user, which means it shouldn't be replaced by the actual loaded node. return; } intent.replacement = node; if (node != null) { if (placeholder.getLabel() != null) { node.setLabel(placeholder.getLabel()); } placeholder.getParent().replaceChild(placeholder, node); } else { //replaced with null means aborted; just remove the placeholder placeholder.removeFromParent(); } } } }; protected static class CatalogLoadIntent extends Intent { private final ICatalogTreeNode placeholder; private final IEclipseContext context; private ICatalogTreeNode replacement; public CatalogLoadIntent(ICatalogTreeNode placeholder, IEclipseContext context) { this.placeholder = placeholder; this.context = context; } } }