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 clazz
054         * @param arguments these must match the arguments given in the initialize method specified in the class
055         * @return metadata object or null if type not available
056         * @throws MetadataException if the class cannot be instantiated, the initialize method does not exist, or
057         *  the initialize method could not be called successfully
058         */
059        public static <T extends MetadataType> T createMetadata(Class<T> clazz, Object... arguments) throws MetadataException {
060                @SuppressWarnings("unchecked")
061                Class<T> mdClass = (Class<T>) metadataClasses.get(clazz);
062                if (mdClass == null) {
063                        return null;
064                }
065
066                T obj = null;
067                try {
068                        obj = mdClass.newInstance();
069                } catch (Exception e) {
070                        throw new MetadataException("Could not create metadata object", e);
071                }
072
073                List<Method> inits = new ArrayList<Method>();
074                for (Method m : mdClass.getMethods()) {
075                        if (m.getName().equals("initialize")) {
076                                inits.add(m);
077                        }
078                }
079
080                if (inits.isEmpty()) {
081                        return obj;
082                }
083
084                int n = arguments == null ? 0 : arguments.length;
085                try {
086                        for (Method m : inits) {
087                                if (m.getParameterTypes().length == n) {
088                                        m.invoke(obj, arguments);
089                                        return obj;
090                                }
091                        }
092                } catch (Exception e) {
093                        throw new MetadataException("Could not initialize object", e);
094                }
095                throw new MetadataException("Could not find initialize method that allows the given number of arguments");
096        }
097
098        /**
099         * Register metadata class
100         * @param clazz
101         */
102        public static <T extends MetadataType> void registerClass(Class<T> clazz) {
103                Class<? extends MetadataType> iClass = LazyDatasetBase.findMetadataTypeSubInterfaces(clazz);
104
105                metadataClasses.put(iClass, clazz);
106        }
107}