| /******************************************************************************* |
| * Copyright (c) 2010 BSI Business Systems Integration AG. |
| * 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: |
| * BSI Business Systems Integration AG - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.scout.commons.serialization; |
| |
| import java.lang.reflect.Modifier; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IProduct; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.scout.commons.StringUtility; |
| import org.eclipse.scout.commons.internal.Activator; |
| import org.eclipse.scout.commons.logger.IScoutLogger; |
| import org.eclipse.scout.commons.logger.ScoutLogManager; |
| import org.eclipse.scout.commons.osgi.BundleListClassLoader; |
| |
| /** |
| * Utility for serializing and deserializing java objects. The utility works in a standard java environment as well as |
| * in an OSGi environment. All classes that are available on the class path or within an OSGi bundle can be |
| * deserialized. |
| * <p/> |
| * The utility uses an environment-dependent {@link IObjectSerializerFactory} for creating {@link IObjectSerializer} |
| * instances. An optional {@link IObjectReplacer} can be used for replacing and resolving objects during the |
| * serialization and deserialization process, respectively. |
| * <p/> |
| * <h3>OSGi Environments</h3> In OSGi Environments, the ordered list of bundle name prefixes used for loading classes |
| * should be configured in the config.ini file or as system property: |
| * <p/> |
| * <code>org.eclipse.scout.commons.serialization.bundleOrderPrefixes</code> |
| * <h3>Custom Strategy</h3> A custom {@link IObjectSerializerFactory} can be provided by a fragment bundle using |
| * <em>org.eclipse.scout.commons</em> as host bundle. The custom {@link IObjectSerializerFactory} class must use the |
| * following fully qualified class name: |
| * <p/> |
| * <code>org.eclipse.scout.commons.serialization.CustomObjectSerializerFactory</code> |
| * |
| * @since 3.8.2 |
| */ |
| public final class SerializationUtility { |
| private static final IScoutLogger LOG; |
| |
| public static final String BUNDLE_ORDER_PREFIX_PROPERTY_NAME = "org.eclipse.scout.commons.serialization.bundleOrderPrefixes"; |
| public static final String ENABLE_RESOURCE_URL_CACHING_PROPERTY_NAME = "org.eclipse.scout.commons.serialization.enableResourceUrlCaching"; |
| public static final String ENABLE_USAGE_OF_BUNDLE_ORDER_PREFIX_LIST_AS_RESOURCE_FILTER_PROPERTY_NAME = "org.eclipse.scout.commons.serialization.enableUsageOfBundleOrderPrefixListAsResourceFilter"; |
| |
| private static final IObjectSerializerFactory FACTORY; |
| |
| static { |
| LOG = ScoutLogManager.getLogger(SerializationUtility.class); |
| FACTORY = createObjectSerializerFactory(); |
| } |
| |
| private SerializationUtility() { |
| // nop |
| } |
| |
| private static IObjectSerializerFactory createObjectSerializerFactory() { |
| IObjectSerializerFactory factory = null; |
| if (Activator.getDefault() != null) { |
| // check whether there is a custom object serializer factory available |
| try { |
| Class<?> customSerializerFactory = Activator.getDefault().getBundle().loadClass("org.eclipse.scout.commons.serialization.CustomObjectSerializerFactory"); |
| LOG.info("loaded custom object serializer factory: [" + customSerializerFactory + "]"); |
| if (!IObjectSerializerFactory.class.isAssignableFrom(customSerializerFactory)) { |
| LOG.warn("custom object serializer factory is not implementing [" + IObjectSerializerFactory.class + "]"); |
| } |
| else if (Modifier.isAbstract(customSerializerFactory.getModifiers())) { |
| LOG.warn("custom object serializer factory is an abstract class [" + customSerializerFactory + "]"); |
| } |
| else { |
| factory = (IObjectSerializerFactory) customSerializerFactory.newInstance(); |
| } |
| } |
| catch (ClassNotFoundException e) { |
| // no custom object serializer factory installed |
| } |
| catch (Exception e) { |
| LOG.warn("Unexpected problem while creating a new instance of custom object serializer factory", e); |
| } |
| |
| // no custom object serializer factory. Use bundle based serializer factory |
| if (factory == null) { |
| factory = new BundleObjectSerializerFactory(); |
| } |
| } |
| else { |
| // running outside eclipse. Use basic strategy. |
| factory = new BasicObjectSerializerFactory(); |
| } |
| |
| return factory; |
| } |
| |
| /** |
| * In OSGi Environments, this method returns the ordered list of bundle name prefixes used for loading classes as it |
| * is configured in the config.ini file or as system property: |
| * <p/> |
| * <code>org.eclipse.scout.commons.serialization.bundleOrderPrefixes</code> |
| * <p/> |
| * If the config.ini or system property is not set or if the method is invoked outside an OSGi environment, a default |
| * value is computed and returned. |
| */ |
| public static String[] getBundleOrderPrefixes() { |
| String rawBundlePrefixes = null; |
| if (Activator.getDefault() != null) { |
| rawBundlePrefixes = Activator.getDefault().getBundle().getBundleContext().getProperty(BUNDLE_ORDER_PREFIX_PROPERTY_NAME); |
| } |
| if (!StringUtility.hasText(rawBundlePrefixes)) { |
| rawBundlePrefixes = System.getProperty(BUNDLE_ORDER_PREFIX_PROPERTY_NAME, null); |
| } |
| if (!StringUtility.hasText(rawBundlePrefixes)) { |
| rawBundlePrefixes = "org.eclipse.scout"; |
| if (Activator.getDefault() != null) { |
| IProduct product = Platform.getProduct(); |
| if (product != null && product.getDefiningBundle() != null && product.getDefiningBundle().getSymbolicName() != null) { |
| String prefix = product.getDefiningBundle().getSymbolicName().replaceAll("^(.*\\.)(client|shared|server|ui)(\\.core)?.*$", "$1"); |
| rawBundlePrefixes = StringUtility.join(",", prefix, rawBundlePrefixes); |
| } |
| } |
| LOG.warn("bundle order prefixes are neither defined in config.ini nor as a system property. Using default value: " + BUNDLE_ORDER_PREFIX_PROPERTY_NAME + "=" + rawBundlePrefixes + ""); |
| } |
| List<String> bundlePrefixes = new ArrayList<String>(); |
| for (String s : StringUtility.split(rawBundlePrefixes, ",")) { |
| s = StringUtility.trim(s); |
| if (StringUtility.hasText(s)) { |
| bundlePrefixes.add(s); |
| } |
| } |
| return bundlePrefixes.toArray(new String[bundlePrefixes.size()]); |
| } |
| |
| /** |
| * The {@link BundleListClassLoader} can cache the resources URLs it finds in the getResource(s) methods. This has the |
| * potential problem, that when bundles get unloaded, the cached resource URLs can't be found anymore. Instead of |
| * building a big check around this, it was safer to only let it enable if this should never be the case. |
| * </br> |
| * This method returns the value as it is configured in the config.ini file or as system property: |
| * <p/> |
| * <code>org.eclipse.scout.commons.serialization.enableResourceUrlCaching</code> |
| * <p/> |
| */ |
| public static boolean isResourceUrlCachingInBundleListClassLoaderEnabled() { |
| String cacheEnabled = null; |
| if (Activator.getDefault() != null) { |
| cacheEnabled = Activator.getDefault().getBundle().getBundleContext().getProperty(ENABLE_RESOURCE_URL_CACHING_PROPERTY_NAME); |
| } |
| if (!StringUtility.hasText(cacheEnabled)) { |
| cacheEnabled = System.getProperty(ENABLE_RESOURCE_URL_CACHING_PROPERTY_NAME, null); |
| } |
| return StringUtility.parseBoolean(cacheEnabled, false); |
| } |
| |
| /** |
| * The methods getResource(s) from {@link BundleListClassLoader} return resources from every bundle from the product |
| * plus from the general classpath. There are cases (library bundles with multiple jars) which this behavior has to be |
| * changed. With this property resources will be filtered the following way: |
| * <ul> |
| * <li>if a resource is found in a bundle which matches the prefix list just this or these resources URLs will be |
| * returned.</li> |
| * <li>if no resource is found in a bundle which matches the prefix list the list will be returned unfiltered.</li> |
| * </ul> |
| * </br> |
| * This method returns the value as it is configured in the config.ini file or as system property: |
| * <p/> |
| * <code>org.eclipse.scout.commons.serialization.enableUsageOfBundleOrderPrefixListAsResourceFilter</code> |
| * <p/> |
| */ |
| public static boolean isUseBundleOrderPrefixListAsResourceFilterEnabled() { |
| String cacheEnabled = null; |
| if (Activator.getDefault() != null) { |
| cacheEnabled = Activator.getDefault().getBundle().getBundleContext().getProperty(ENABLE_USAGE_OF_BUNDLE_ORDER_PREFIX_LIST_AS_RESOURCE_FILTER_PROPERTY_NAME); |
| } |
| if (!StringUtility.hasText(cacheEnabled)) { |
| cacheEnabled = System.getProperty(ENABLE_USAGE_OF_BUNDLE_ORDER_PREFIX_LIST_AS_RESOURCE_FILTER_PROPERTY_NAME, null); |
| } |
| return StringUtility.parseBoolean(cacheEnabled, false); |
| } |
| |
| /** |
| * Uses a {@link IObjectSerializerFactory} for creating a new {@link IObjectSerializer}. |
| * |
| * @return Returns a new {@link IObjectSerializer}. |
| */ |
| public static IObjectSerializer createObjectSerializer() { |
| return createObjectSerializer(null); |
| } |
| |
| /** |
| * Uses a {@link IObjectSerializerFactory} for creating a new {@link IObjectSerializer} which uses the given |
| * {@link IObjectReplacer} for substituting objects during the serializing and deserializing process. |
| * |
| * @return Returns a new {@link IObjectSerializer}. |
| */ |
| public static IObjectSerializer createObjectSerializer(IObjectReplacer objectReplacer) { |
| return FACTORY.createObjectSerializer(objectReplacer); |
| } |
| |
| /** |
| * @return Returns an environment-dependent {@link ClassLoader} that is able to load all classes that are available in |
| * the running environment. |
| */ |
| public static ClassLoader getClassLoader() { |
| return FACTORY.getClassLoader(); |
| } |
| } |