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