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
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.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
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}