    001/*******************************************************************************
    002 * Copyright (c) 2016 Diamond Light Source Ltd. and others.
    003 * All rights reserved. This program and the accompanying materials
    004 * are made available under the terms of the Eclipse Public License v1.0
    005 * which accompanies this distribution, and is available at
    006 * http://www.eclipse.org/legal/epl-v10.html
    007 *
    008 * Contributors:
    009 *     Diamond Light Source Ltd - initial API and implementation
    010 *******************************************************************************/
    011package org.eclipse.january.metadata;
    012
    013import java.lang.reflect.Method;
    014import java.util.ArrayList;
    015import java.util.HashMap;
    016import java.util.List;
    017import java.util.Map;
    018
    019import org.eclipse.january.MetadataException;
    020import org.eclipse.january.dataset.LazyDatasetBase;
    021import org.eclipse.january.metadata.internal.AxesMetadataImpl;
    022import org.eclipse.january.metadata.internal.DimensionMetadataImpl;
    023import org.eclipse.january.metadata.internal.ErrorMetadataImpl;
    024import org.eclipse.january.metadata.internal.MaskMetadataImpl;
    025import org.eclipse.january.metadata.internal.OriginMetadataImpl;
    026import org.eclipse.january.metadata.internal.PeemMetadataImpl;
    027import org.eclipse.january.metadata.internal.StatisticsMetadataImpl;
    028import org.eclipse.january.metadata.internal.UnitMetadataImpl;
    029
    030public class MetadataFactory {
    031
    032        private MetadataFactory() {
    033        }
    034
    035        static Map<Class<? extends MetadataType>, Class<? extends MetadataType>> metadataClasses = createMap();
    036        private static Map<Class<? extends MetadataType>, Class<? extends MetadataType>> createMap() {
    037                Map<Class<? extends MetadataType>, Class<? extends MetadataType>> map = new HashMap<Class<? extends MetadataType>, Class<? extends MetadataType>>();
    038                map.put(IMetadata.class, Metadata.class);
    039                map.put(ErrorMetadata.class, ErrorMetadataImpl.class);
    040                map.put(AxesMetadata.class, AxesMetadataImpl.class);
    041                map.put(DimensionMetadata.class, DimensionMetadataImpl.class);
    042                map.put(MaskMetadata.class, MaskMetadataImpl.class);
    043                map.put(OriginMetadata.class, OriginMetadataImpl.class);
    044                map.put(PeemMetadata.class, PeemMetadataImpl.class);
    045                map.put(StatisticsMetadata.class, StatisticsMetadataImpl.class);
    046                map.put(UnitMetadata.class, UnitMetadataImpl.class);
    047                return map;
    048        }
    049
    050
    051        /**
    052         * Create a metadata object of given class with given arguments
    053         * @param <T> metadata type
    054         * @param clazz metadata class
    055         * @param arguments these must match the arguments given in the initialize method specified in the class
    056         * @return metadata object or null if type not available
    057         * @throws MetadataException if the class cannot be instantiated, the initialize method does not exist, or
    058         *  the initialize method could not be called successfully
    059         */
    060        public static <T extends MetadataType> T createMetadata(Class<T> clazz, Object... arguments) throws MetadataException {
    061                @SuppressWarnings("unchecked")
    062                Class<T> mdClass = (Class<T>) metadataClasses.get(clazz);
    063                if (mdClass == null) {
    064                        return null;
    065                }
    066
    067                T obj = null;
    068                try {
    069                        obj = mdClass.getConstructor().newInstance();
    070                } catch (Exception e) {
    071                        throw new MetadataException("Could not create metadata object", e);
    072                }
    073
    074                List<Method> inits = new ArrayList<Method>();
    075                for (Method m : mdClass.getMethods()) {
    076                        if (m.getName().equals("initialize")) {
    077                                inits.add(m);
    078                        }
    079                }
    080
    081                if (inits.isEmpty()) {
    082                        return obj;
    083                }
    084
    085                int n = arguments == null ? 0 : arguments.length;
    086                try {
    087                        for (Method m : inits) {
    088                                if (m.getParameterTypes().length == n) {
    089                                        m.invoke(obj, arguments);
    090                                        return obj;
    091                                }
    092                        }
    093                } catch (Exception e) {
    094                        throw new MetadataException("Could not initialize object", e);
    095                }
    096                throw new MetadataException("Could not find initialize method that allows the given number of arguments");
    097        }
    098
    099        /**
    100         * Register metadata class
    101         * @param <T> metadata type
    102         * @param clazz metadata class
    103         */
    104        public static <T extends MetadataType> void registerClass(Class<T> clazz) {
    105                Class<? extends MetadataType> iClass = LazyDatasetBase.findMetadataTypeSubInterfaces(clazz);
    106
    107                metadataClasses.put(iClass, clazz);
    108        }
    109}