--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2019 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * 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
+ *
+ * Contributors:
+ * Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.internal;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.simantics.UnhandledExceptionService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Antti Villberg
+ */
+public class UnhandledExceptionServiceImpl implements UnhandledExceptionService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(UnhandledExceptionServiceImpl.class);
+ private static ServiceRegistration<?> service = null;
+
+ private final List<Consumer<Throwable>> handlers = new ArrayList<>();
+
+ /**
+ * Invoked by the bundle activator to initialize the cache service.
+ *
+ * @param context the bundle context to register the service with
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public synchronized static void initialize(BundleContext context) {
+ if (service == null) {
+ service = context.registerService(UnhandledExceptionService.class.getName(), new UnhandledExceptionServiceImpl(), new Hashtable());
+ }
+ }
+
+ /**
+ * Invoked by the bundle activator to close the cache service.
+ */
+ public synchronized static void close() {
+ if (service != null) {
+ service.unregister();
+ service = null;
+ }
+ }
+
+ @Override
+ public synchronized void registerHandler(Consumer<Throwable> handler) {
+ handlers.add(handler);
+ }
+
+ @Override
+ public synchronized void handle(Throwable t) {
+ for (Consumer<Throwable> handler : handlers) {
+ try {
+ handler.accept(t);
+ } catch (Exception e) {
+ handleException(handler, e);
+ } catch (LinkageError e) {
+ handleException(handler, e);
+ } catch (AssertionError e) {
+ handleException(handler, e);
+ }
+ }
+ }
+
+ protected void handleException(Object source, Throwable t) {
+ LOGGER.error("{}: Unhandled exception handler {} caused unexpected exception", getClass().getSimpleName(), source, t);
+ }
+
+}