001package org.cache2k.storage;
002
003/*
004 * #%L
005 * cache2k core package
006 * %%
007 * Copyright (C) 2000 - 2015 headissue GmbH, Munich
008 * %%
009 * This program is free software: you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as
011 * published by the Free Software Foundation, either version 3 of the 
012 * License, or (at your option) any later version.
013 * 
014 * This program is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 * 
019 * You should have received a copy of the GNU General Public 
020 * License along with this program.  If not, see
021 * <http://www.gnu.org/licenses/gpl-3.0.html>.
022 * #L%
023 */
024
025import java.util.HashMap;
026import java.util.HashSet;
027import java.util.Map;
028import java.util.ServiceLoader;
029import java.util.Set;
030
031/**
032 * Singleton which provides a top level MarshallerFactory which
033 * in turn delegates to marshaller factories that are registered
034 * via the service loader.
035 *
036 * @author Jens Wilke; created: 2014-04-19
037 */
038public class Marshallers implements MarshallerFactory {
039
040  private static ServiceLoader<? extends MarshallerFactory> loader =
041    ServiceLoader.load(MarshallerFactory.class);
042
043  private static MarshallerFactory instance;
044
045  public static MarshallerFactory getInstance() {
046    if (instance == null) {
047      instance = new Marshallers();
048    }
049    return instance;
050  }
051
052  private Set<MarshallerFactory> factorySet = new HashSet<MarshallerFactory>();
053  private Map<Class<?>, MarshallerFactory> type2factory = new HashMap<Class<?>, MarshallerFactory>();
054  private Map<Class<?>, MarshallerFactory> factoryType2factory = new HashMap<Class<?>, MarshallerFactory>();
055
056  /**
057   * Directly register a marshallerfactory. This is an alternative to the automatic
058   * discovery via the service loader. Useful to provide a marshaller for a
059   * custom bean and register it within the class load (static constructor section).
060   */
061  public synchronized void registerMarshallerFactory(MarshallerFactory f) {
062    factorySet.add(f);
063    type2factory.clear();
064    factoryType2factory.clear();
065  }
066
067  @Override
068  public Class<?> getType() {
069    return Object.class;
070  }
071
072  @Override
073  public int getPriority() {
074    return 0;
075  }
076
077  @Override
078  public synchronized Marshaller createMarshaller(Class<?> _type) {
079    return resolveFactory(_type).createMarshaller(_type);
080  }
081
082  @Override
083  public synchronized Marshaller createMarshaller(Parameters c) {
084    if (c.getMarshallerFactory() != null) {
085      MarshallerFactory f = factoryType2factory.get(c.getMarshallerFactory());
086      if (f == null) {
087        try {
088          f = (MarshallerFactory) c.getMarshallerFactory().newInstance();
089        } catch (Exception e) {
090          throw new IllegalArgumentException(e);
091        }
092        factoryType2factory.put(c.getMarshallerFactory(), f);
093      }
094      return f.createMarshaller(c);
095    }
096    try {
097      Marshaller m = (Marshaller) c.getMarshallerType().newInstance();
098      return m;
099    } catch (Exception e) {
100      throw new IllegalArgumentException(e);
101    }
102  }
103
104  MarshallerFactory resolveFactory(Class<?> _type) {
105    MarshallerFactory f = type2factory.get(_type);
106    if (f != null) {
107      return f;
108    }
109    for (MarshallerFactory i : loader) {
110      factorySet.add(i);
111    }
112    for (MarshallerFactory i : factorySet) {
113      if (i.getType().isAssignableFrom(_type)) {
114        if (f == null || f.getPriority() < i.getPriority()) {
115          f = i;
116        }
117      }
118    }
119    type2factory.put(_type, f);
120    return f;
121  }
122
123}