/*
* 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.karaf.system.internal;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.apache.felix.utils.properties.Properties;
import org.apache.karaf.system.FrameworkType;
import org.apache.karaf.system.SystemService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.startlevel.FrameworkStartLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of the system service.
*/
public class SystemServiceImpl implements SystemService {
private static final Logger LOGGER = LoggerFactory.getLogger(SystemServiceImpl.class);
private BundleContext bundleContext;
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public BundleContext getBundleContext() {
return this.bundleContext;
}
public void halt() throws Exception {
halt(null);
}
public void halt(String time) throws Exception {
shutdown(timeToSleep(time));
}
public void reboot() throws Exception {
reboot(null, Swipe.NONE);
}
public void reboot(String time, Swipe cleanup) throws Exception {
reboot(timeToSleep(time), cleanup);
}
private void shutdown(final long sleep) {
new Thread() {
public void run() {
try {
sleepWithMsg(sleep, "Shutdown in " + sleep / 1000 / 60 + " minute(s)");
getBundleContext().getBundle(0).stop();
} catch (Exception e) {
LOGGER.error("Halt error", e);
}
}
}.start();
}
private void reboot(final long sleep, final Swipe clean) {
new Thread() {
public void run() {
try {
sleepWithMsg(sleep, "Reboot in " + sleep / 1000 / 60 + " minute(s)");
System.setProperty("karaf.restart", "true");
if (clean.equals(Swipe.ALL)) {
System.setProperty("karaf.clean.all", "true");
} else if (clean.equals(Swipe.CACHE)) {
System.setProperty("karaf.clean.cache", "true");
}
bundleContext.getBundle(0).stop();
} catch (Exception e) {
LOGGER.error("Reboot error", e);
}
}
}.start();
}
private void sleepWithMsg(final long sleep, String msg)
throws InterruptedException {
if (sleep > 0) {
LOGGER.info(msg);
System.err.println(msg);
}
Thread.sleep(sleep);
}
public void setStartLevel(int startLevel) throws Exception {
getBundleContext().getBundle(0).adapt(FrameworkStartLevel.class).setStartLevel(startLevel);
}
public int getStartLevel() throws Exception {
return getBundleContext().getBundle(0).adapt(FrameworkStartLevel.class).getStartLevel();
}
/**
* Convert a time string to sleep period (in millisecond).
*
* @param time the time string.
* @return the corresponding sleep period in millisecond.
*/
private long timeToSleep(String time) throws Exception {
long sleep = 0;
if (time != null) {
if (!time.equals("now")) {
if (time.contains(":")) {
// try to parse the date in hh:mm
String[] strings = time.split(":");
if (strings.length != 2) {
throw new IllegalArgumentException("Time " + time + " is not valid (not in hour:minute format)");
}
int hour = Integer.parseInt(strings[0]);
int minute = Integer.parseInt(strings[1]);
if (hour < 0 || hour > 23) {
throw new IllegalArgumentException("Time " + time + " is not valid (hour " + hour + " is not between 0 and 23)");
}
if (minute < 0 || minute > 59) {
throw new IllegalArgumentException("Time " + time + " is not valid (minute " + minute + " is not between 0 and 59)");
}
GregorianCalendar currentDate = new GregorianCalendar();
GregorianCalendar shutdownDate = new GregorianCalendar(currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DAY_OF_MONTH), Integer.parseInt(strings[0]), Integer.parseInt(strings[1]));
if (shutdownDate.before(currentDate)) {
shutdownDate.set(Calendar.DATE, shutdownDate.get(Calendar.DATE) + 1);
}
sleep = shutdownDate.getTimeInMillis() - currentDate.getTimeInMillis();
} else {
if (time.startsWith("+")) {
time = time.substring(1);
}
try {
sleep = Long.parseLong(time) * 60 * 1000;
} catch (Exception e) {
throw new IllegalArgumentException("Time " + time + " is not valid");
}
}
}
}
return sleep;
}
@Override
public String getVersion() {
return System.getProperty("karaf.version");
}
@Override
public String getName() {
return bundleContext.getProperty("karaf.name");
}
@Override
public void setName(String name) {
try {
String karafEtc = bundleContext.getProperty("karaf.etc");
File etcDir = new File(karafEtc);
File syspropsFile = new File(etcDir, "system.properties");
FileInputStream fis = new FileInputStream(syspropsFile);
Properties props = new Properties();
props.load(fis);
fis.close();
props.setProperty("karaf.name", name);
FileOutputStream fos = new FileOutputStream(syspropsFile);
props.store(fos, "");
fos.close();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public FrameworkType getFramework() {
if (bundleContext.getBundle(0).getSymbolicName().contains("felix")) {
return FrameworkType.felix;
} else {
return FrameworkType.equinox;
}
}
private Properties loadProps() throws IOException {
return new Properties(new File(System.getProperty("karaf.etc"), "config.properties"));
}
public void setFramework(FrameworkType framework) {
if (framework == null) {
return;
}
try {
Properties properties = loadProps();
properties.put("karaf.framework", framework.name());
properties.save();
} catch (IOException e) {
throw new RuntimeException("Error setting framework: " + e.getMessage(), e);
}
}
public void setFrameworkDebug(boolean debug) {
try {
Properties properties = loadProps();
if (debug) {
properties.put("felix.log.level", "4");
properties.put("osgi.debug", "etc/equinox-debug.properties");
} else {
properties.remove("felix.log.level");
properties.remove("osgi.debug");
}
// TODO populate the equinox-debug.properties file with the one provided in shell/dev module
properties.save();
} catch (IOException e) {
throw new RuntimeException("Error setting framework debugging: " + e.getMessage(), e);
}
}
@Override
public String setSystemProperty(String key, String value, boolean persist) {
if (persist) {
try {
String etc = System.getProperty("karaf.etc");
Properties props = new Properties(new File(etc, "system.properties"));
props.put(key, value);
props.save();
} catch (IOException e) {
throw new RuntimeException("Error persisting system property", e);
}
}
return System.setProperty(key, value);
}
}