/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG and others.
* 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.core;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.FrameworkUtil;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.NativeCodeSpecification;
import org.eclipse.osgi.service.resolver.PlatformAdmin;
import org.eclipse.osgi.service.resolver.State;
import org.eclipse.osgi.service.resolver.VersionConstraint;
import org.eclipse.osgi.util.NLS;
import org.eclipse.riena.core.service.Service;
import org.eclipse.riena.core.util.VariableManagerUtil;
import org.eclipse.riena.internal.core.Activator;
/**
* Utility to check the Riena status.
*/
public final class RienaStatus {
/**
* This system property controls {@code RienaStatus.isDevelopment()}
*/
public static final String RIENA_DEVELOPMENT_SYSTEM_PROPERTY = "riena.development"; //$NON-NLS-1$
/**
* This system property controls {@code RienaStatus.isTest()}
*/
public static final String RIENA_TEST_SYSTEM_PROPERTY = "riena.test"; //$NON-NLS-1$
/**
* This is the default value (i.e. if the value is not explicitly defined)
* for the system property {@code RIENA_DEVELOPMENT_SYSTEM_PROPERTY}
*/
public static final String DEVELOPMENT_DEFAULT = inOsgiDevMode();
/**
* This is the default value (i.e. if the value is not explicitly defined)
* for the system property {@code RIENA_TEST_SYSTEM_PROPERTY}
*/
public static final String TEST_DEFAULT = "false"; //$NON-NLS-1$
/**
* Value of {@code getStage()} if no stage has been defined.
*
* @since 3.0
*/
public static final String UNKNOWN_STAGE = "<unknown>"; //$NON-NLS-1$
private static final String BUNDLE_UNRESOLVED_EXCEPTION = "The bundle \"{0}\" could not be resolved"; //$NON-NLS-1$
private static final String BUNDLE_UNRESOLVED_STATE_CONFLICT = "The state indicates the bundle is resolved"; //$NON-NLS-1$
private static final String BUNDLE_UNRESOLVED_UNSATISFIED_CONSTRAINT_EXCEPTION = "The bundle \"{0}\" could not be resolved. Reason: {1}"; //$NON-NLS-1$
private RienaStatus() {
// Utility
}
/**
* Riena core bundle status.
*
* @return {@code true} if the riena.core bundle has been started; otherwise
* {@code false}
*/
public static boolean isActive() {
if (Activator.getDefault() == null) {
return false;
}
return Activator.getDefault().isActive();
}
/**
* Are all riena startup actions executed?
*
* @return {@code true} if all startup actions have been executed; otherwise
* {@code false}
*
* @since 3.0
*/
public static boolean areStartupActionsExecuted() {
return Activator.getDefault().areStartupActionsExecuted();
}
/**
* Are we in <i>development</i>?<br>
* If {@code true} certain services/functionalities behave more appropriate
* for development time, e.g.
* <ul>
* <li>default logging is enabled</li>
* <li>the store of the client monitoring is cleaned up on each start
* <li>..</li>
* </ul>
* <b>Note:</b> This property is controlled by the system property
* "riena.development". If <b>NOT</b> defined it defaults to
* {@code System.getProperty("osgi.dev") != null}.<br>
* This means that the default value is {@code true} while you are within
* the Eclipse IDE otherwise it is {@code false}.
*
* @return is development or not?
*/
public static boolean isDevelopment() {
return Boolean.parseBoolean(System.getProperty(RIENA_DEVELOPMENT_SYSTEM_PROPERTY, DEVELOPMENT_DEFAULT));
}
private static String inOsgiDevMode() {
return Boolean.toString(System.getProperty("osgi.dev") != null); //$NON-NLS-1$
}
/**
* Are we running a <i>test case</i>?<br>
* If {@code true} certain services/functionalities behave more appropriate
* for testing, e.g. ridgets are created on the fly
*
* @return whether we are running a test
*
* @since 2.0
*/
public static boolean isTest() {
return Boolean.parseBoolean(System.getProperty(RIENA_TEST_SYSTEM_PROPERTY, TEST_DEFAULT));
}
/**
* Return the stage riena is currently running in.
*
* @return the stage or if not set the string {@code "<unknown>"}
* @since 3.0
*/
public static String getStage() {
try {
return VariableManagerUtil.substitute("${riena.stage}"); //$NON-NLS-1$
} catch (final CoreException e) {
return UNKNOWN_STAGE;
}
}
/**
* Create a "nice" report with a list of all unresolved bundles and their
* possible cause for not becoming resolved.
*
* @return the report or {@code null} if all bundles were resolved
*
* @since 4.0
*/
public static String reportUnresolvedBundles() {
final Bundle coreBundle = FrameworkUtil.getBundle(RienaStatus.class);
if (coreBundle == null) {
return "Could not resolve Riena core bundle."; //$NON-NLS-1$
}
final BundleContext bundleContext = coreBundle.getBundleContext();
if (bundleContext == null) {
return "Could not get Riena bundle context."; //$NON-NLS-1$
}
final StringBuilder bob = new StringBuilder();
for (final Bundle bundle : bundleContext.getBundles()) {
if (bundle.getState() < Bundle.RESOLVED) {
if (bob.length() == 0) {
bob.append("Unresolved bundles:").append("\n"); //$NON-NLS-1$//$NON-NLS-2$
}
bob.append(" - ").append(bundle.getSymbolicName()).append(" is not resolved"); //$NON-NLS-1$ //$NON-NLS-2$
try {
final PlatformAdmin platformAdmin = Service.get(bundleContext, PlatformAdmin.class);
final BundleException resolutionFailureException = getResolutionFailureException(bundle, platformAdmin);
if (resolutionFailureException != null) {
bob.append(" because: ").append(resolutionFailureException.getMessage()); //$NON-NLS-1$
}
} catch (final Exception e) {
bob.append("A problem occured while trying to compute the reason. " + e.getMessage()); //$NON-NLS-1$
}
bob.append("\n"); //$NON-NLS-1$
}
}
return bob.length() == 0 ? null : bob.toString();
}
private static BundleException getResolutionFailureException(final Bundle bundle, final PlatformAdmin platformAdmin) {
final State state = platformAdmin.getState();
final BundleDescription bundleDescription = state.getBundle(bundle.getBundleId());
if (bundleDescription == null) {
return new BundleException(NLS.bind(BUNDLE_UNRESOLVED_EXCEPTION, bundle.toString()), BundleException.RESOLVE_ERROR);
}
// just a sanity check - this would be an inconsistency between the framework and the state
if (bundleDescription.isResolved()) {
return new BundleException(BUNDLE_UNRESOLVED_STATE_CONFLICT, BundleException.RESOLVE_ERROR);
}
return getResolverError(bundle, bundleDescription, platformAdmin);
}
private static BundleException getResolverError(final Bundle bundle, final BundleDescription bundleDesc,
final PlatformAdmin platformAdmin) {
final VersionConstraint[] errors = platformAdmin.getStateHelper().getUnsatisfiedConstraints(bundleDesc);
// final ResolverError[] errors = state.getResolverErrors(bundleDesc);
if (errors == null || errors.length == 0) {
return new BundleException(NLS.bind(BUNDLE_UNRESOLVED_EXCEPTION, bundle.toString()), BundleException.RESOLVE_ERROR);
}
final StringBuffer message = new StringBuffer();
int errorType = BundleException.RESOLVE_ERROR;
for (int i = 0; i < errors.length; i++) {
if (errors[i] instanceof NativeCodeSpecification) {
errorType = BundleException.NATIVECODE_ERROR;
}
message.append(errors[i].toString());
if (i < errors.length - 1) {
message.append(", "); //$NON-NLS-1$
}
}
return new BundleException(NLS.bind(BUNDLE_UNRESOLVED_UNSATISFIED_CONSTRAINT_EXCEPTION, bundle.toString(), message.toString()), errorType);
}
}