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}