blob: 373c06030e480a08cbf29faa8abcf36221c4b2cc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.sling.launchpad.base.impl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import org.apache.felix.framework.Felix;
import org.apache.sling.launchpad.base.shared.Loader;
import org.apache.sling.launchpad.base.shared.Notifiable;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.framework.FrameworkEvent;
public class SlingFelix extends Felix {
private final Notifiable notifiable;
private Thread notifierThread;
// see getBundle(Class) below
private Method getBundleMethod;
public SlingFelix(final Notifiable notifiable, @SuppressWarnings("rawtypes") final Map props) throws Exception {
super(props);
this.notifiable = notifiable;
}
@Override
public void update() throws BundleException {
update(null);
}
@Override
public void update(final InputStream is) throws BundleException {
// get the update file and make sure, the stream is closed
try {
startNotifier(true, is);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ignore) {
}
}
}
// just stop the framework now
super.stop();
}
public void restart() throws BundleException {
super.stop();
}
@Override
public void stop() throws BundleException {
startNotifier(false, null);
super.stop();
}
@Override
public void stop(final int status) throws BundleException {
startNotifier(false, null);
super.stop(status);
}
private synchronized void startNotifier(final boolean restart, final InputStream ins) {
if (notifierThread == null) {
notifierThread = new Thread(new Notifier(restart, ins),
"Sling Notifier");
notifierThread.setDaemon(false);
notifierThread.start();
}
}
/**
* Returns the bundle from which the given class has been loaded or
* <code>null</code> if the class has not been loaded through any
* of the bundles in this framework.
* <p>
* This method delegates to Felix.getBundle(Class) to support the
* URLHandlers service implementation. See SLING-2554 for details.
*
* @param clazz The class to check
*
* @return The Bundle or <code>null</code> if the class has not been
* loaded through any of the bundles in this framework.
*/
public Bundle getBundle(Class<?> clazz) {
Method getBundleMethod = this.getBundleMethod;
if (getBundleMethod == null) {
Class<?> provider = Felix.class; // super class actually
try {
getBundleMethod = provider.getDeclaredMethod("getBundle", Class.class);
getBundleMethod.setAccessible(true);
this.getBundleMethod = getBundleMethod;
} catch (Exception e) {
throw new NoSuchMethodError("getBundle");
}
}
try {
return (Bundle) getBundleMethod.invoke(this, clazz);
} catch (IllegalArgumentException e) {
// we don't expect this, we checked everything
} catch (IllegalAccessException e) {
// we don't expect this, because we set the method accessible
} catch (InvocationTargetException e) {
// unpack and rethrow
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
}
return null;
}
private class Notifier implements Runnable {
private final boolean restart;
private final File updateFile;
private Notifier(final boolean restart, final InputStream ins) {
this.restart = restart;
if (ins != null) {
File tmpFile;
try {
tmpFile = File.createTempFile("slingupdate", ".jar");
Loader.spool(ins, tmpFile);
} catch (IOException ioe) {
// TOOD: log
tmpFile = null;
}
this.updateFile = tmpFile;
} else {
this.updateFile = null;
}
}
@Override
public void run() {
boolean restart = this.restart;
try {
if (SlingFelix.this.waitForStop(0).getType() == FrameworkEvent.STOPPED_SYSTEM_REFRESHED) {
restart = true;
}
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
if (restart) {
SlingFelix.this.notifiable.updated(updateFile);
} else {
SlingFelix.this.notifiable.stopped();
}
}
}
}