    001/*-
    002 *******************************************************************************
    003 * Copyright (c) 2011, 2016 Diamond Light Source Ltd.
    004 * All rights reserved. This program and the accompanying materials
    005 * are made available under the terms of the Eclipse Public License v1.0
    006 * which accompanies this distribution, and is available at
    007 * http://www.eclipse.org/legal/epl-v10.html
    008 *
    009 * Contributors:
    010 *    Peter Chang - initial API and implementation and/or initial documentation
    011 *******************************************************************************/
    012
    013package org.eclipse.january.metadata;
    014
    015import java.io.ByteArrayInputStream;
    016import java.io.ByteArrayOutputStream;
    017import java.io.ObjectInputStream;
    018import java.io.ObjectOutputStream;
    019import java.io.Serializable;
    020import java.util.Collection;
    021import java.util.Collections;
    022import java.util.HashMap;
    023import java.util.LinkedHashMap;
    024import java.util.Map;
    025import java.util.Map.Entry;
    026
    027import org.eclipse.january.MetadataException;
    028import org.eclipse.january.dataset.ShapeUtils;
    029
    030
    031/**
    032 * Basic implementation of metadata
    033 */
    034public class Metadata implements IMetadata {
    035        private static final long serialVersionUID = IMetadata.serialVersionUID;
    036
    037        private Map<String, ? extends Serializable> metadata;
    038        // NOTE shapes is LinkedHashMap here because the names collection
    039        // maintained order. Now that we do not need this collection but if we
    040        // do not keep the shapes in a LinkedHashMap, we lose order.
    041        private Map<String,int[]> shapes = new LinkedHashMap<String,int[]>(7);
    042        private Collection<Serializable> userObjects;
    043        private String filePath;
    044
    045
    046        public Metadata() {
    047        }
    048
    049        public Metadata(Map<String, ? extends Serializable> metadata) {
    050                initialize(metadata);
    051        }
    052
    053        @Override
    054        public void initialize(Map<String, ? extends Serializable> metadata) {
    055                this.metadata = metadata;
    056        }
    057
    058        @Override
    059        public void addNames(Collection<String> names) {
    060                if (names != null) {
    061                        for (String n : names) {
    062                                shapes.put(n, null);
    063                        }
    064                }
    065        }
    066
    067        /**
    068         * Set metadata map
    069         * @param metadata map
    070         */
    071        @Override
    072        public void setMetadata(Map<String, ? extends Serializable> metadata) {
    073                this.metadata = metadata;
    074        }
    075
    076        /**
    077         * Internal use only
    078         * @return metadata map
    079         */
    080        protected Map<String, ? extends Serializable> getInternalMetadata() {
    081                return metadata;
    082        }
    083
    084        /**
    085         * Set user objects
    086         * @param objects for user
    087         */
    088        public void setUserObjects(Collection<Serializable> objects) {
    089                userObjects = objects;
    090        }
    091
    092        public void addDataInfo(String name, int... shape) {
    093                shapes.put(name, shape);
    094        }
    095
    096        @Override
    097        public Collection<String> getDataNames() {
    098                return Collections.unmodifiableCollection(shapes.keySet());
    099        }
    100
    101        @Override
    102        public Map<String, int[]> getDataShapes() {
    103                return Collections.unmodifiableMap(shapes);
    104        }
    105
    106        @Override
    107        public Map<String, Integer> getDataSizes() {
    108                Map<String, Integer> sizes = new HashMap<String, Integer>(1);
    109                for (Entry<String, int[]> e : shapes.entrySet()) {
    110                        int[] shape = e.getValue();
    111                        if (shape != null && shape.length > 1)
    112                                sizes.put(e.getKey(), ShapeUtils.calcSize(shape));
    113                        else
    114                                sizes.put(e.getKey(), null);
    115                }
    116                if (sizes.size() > 0) {
    117                        return Collections.unmodifiableMap(sizes);
    118                }
    119                return null;
    120        }
    121
    122        @Override
    123        public Serializable getMetaValue(String key) throws MetadataException {
    124                return metadata == null ? null : metadata.get(key);
    125        }
    126
    127        @SuppressWarnings("unchecked")
    128        @Override
    129        public Collection<String> getMetaNames() throws MetadataException {
    130                return metadata == null ? (Collection<String>) Collections.EMPTY_SET : Collections.unmodifiableCollection(metadata.keySet());
    131        }
    132
    133        @Override
    134        public Collection<Serializable> getUserObjects() {
    135                return userObjects;
    136        }
    137
    138        @Override
    139        public IMetadata clone() {
    140                Metadata c = null;
    141                try {
    142                        c = (Metadata) super.clone();
    143                        if (metadata != null) {
    144                                HashMap<String, Serializable> md = new HashMap<String, Serializable>();
    145                                c.metadata = md;
    146                                ByteArrayOutputStream os = new ByteArrayOutputStream(512);
    147                                for (String k : metadata.keySet()) {
    148                                        Serializable v = metadata.get(k);
    149                                        if (v != null) {
    150                                                try (ObjectOutputStream oos = new ObjectOutputStream(os)) {
    151                                                        oos.writeObject(v);
    152                                                        try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(os.toByteArray()))) {
    153                                                                Serializable nv = (Serializable) ois.readObject();
    154                                                                md.put(k, nv);
    155                                                        }
    156                                                }
    157                                                os.reset();
    158                                        } else {
    159                                                md.put(k, null);
    160                                        }
    161                                }
    162                        }
    163                        c.shapes = new HashMap<String, int[]>(1);
    164                        for (Entry<String, int[]> e : shapes.entrySet()) {
    165                                int[] s = e.getValue();
    166                                c.shapes.put(e.getKey(), s == null ? null : s.clone());
    167                        }
    168                } catch (CloneNotSupportedException e) {
    169                        // Allowed for some objects not to be cloned.
    170                } catch (Throwable e) {
    171                        if (e instanceof ClassNotFoundException) {
    172                                // Fix to http://jira.diamond.ac.uk/browse/SCI-1644
    173                                // Happens when cloning meta data with GridPreferences
    174                        } if (e instanceof RuntimeException ) {
    175                           throw (RuntimeException)e;
    176                        }
    177                }
    178                return c;
    179        }
    180
    181        @Override
    182        public String getFilePath() {
    183                return filePath;
    184        }
    185
    186        @Override
    187        public void setFilePath(String filePath) {
    188                this.filePath = filePath;
    189        }
    190}