001/*
002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 * $Id$
020 */
021
022package org.nuxeo.ecm.platform.importer.properties;
023
024import java.io.File;
025import java.io.FileInputStream;
026import java.io.IOException;
027import java.io.Serializable;
028import java.util.ArrayList;
029import java.util.Collections;
030import java.util.Enumeration;
031import java.util.HashMap;
032import java.util.List;
033import java.util.Map;
034import java.util.Properties;
035import java.util.concurrent.locks.ReentrantReadWriteLock;
036import java.util.regex.Pattern;
037
038import org.apache.commons.io.FilenameUtils;
039import org.apache.commons.lang.StringUtils;
040
041/**
042 * Collects meta-data from a FileSystem and manage inheritence
043 *
044 * @author Thierry Delprat
045 */
046public class MetadataCollector {
047
048    public static final boolean staticInherit = true;
049
050    public static final boolean useIntrospection = false;
051
052    public static String DATE_FORMAT = "MM/dd/yyyy";
053
054    public static String LIST_SEPARATOR = "|";
055
056    public static String REGEXP_LIST_SEPARATOR = "\\|";
057
058    public static String ARRAY_SEPARATOR = "||";
059
060    public static String REGEXP_ARRAY_SEPARATOR = "\\|\\|";
061
062    protected Map<String, Map<String, Serializable>> collectedMetadata = new HashMap<String, Map<String, Serializable>>();
063
064    protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
065
066    public void addPropertiesFromStrings(String contextPath, Map<String, String> properties) {
067        Map<String, Serializable> collectedProperties = new HashMap<String, Serializable>();
068        for (String name : properties.keySet()) {
069            Serializable value = parseFromString(name, properties.get(name));
070            collectedProperties.put(name, value);
071        }
072        addProperties(contextPath, collectedProperties);
073    }
074
075    public void addProperties(String contextPath, Map<String, Serializable> collectedProperties) {
076        try {
077            lock.writeLock().lock();
078            contextPath = FilenameUtils.normalizeNoEndSeparator(contextPath);
079            if (staticInherit) {
080                File file = new File(contextPath);
081                while (!StringUtils.isEmpty(file.getParent())) {
082                    file = file.getParentFile();
083                    Map<String, Serializable> parentProperties = collectedMetadata.get(file.toString());
084                    if (parentProperties != null) {
085                        for (String name : parentProperties.keySet()) {
086                            if (!collectedProperties.containsKey(name)) {
087                                collectedProperties.put(name, parentProperties.get(name));
088                            }
089                        }
090                    }
091                }
092            }
093            collectedMetadata.put(contextPath, collectedProperties);
094        } finally {
095            lock.writeLock().unlock();
096        }
097
098    }
099
100    protected static Pattern numPattern = Pattern.compile("([0-9\\,\\.\\+\\-]+)");
101
102    protected Serializable parseFromString(String name, String value) {
103
104        Serializable prop = value;
105        if (useIntrospection) {
106            throw new UnsupportedOperationException("Introspection mode not available");
107        } else {
108            if (value.contains(ARRAY_SEPARATOR)) {
109                prop = value.split(REGEXP_ARRAY_SEPARATOR);
110            } else if (value.contains(LIST_SEPARATOR)) {
111                List<Serializable> lstprop = new ArrayList<Serializable>();
112                String[] parts = value.split(REGEXP_LIST_SEPARATOR);
113                for (String part : parts) {
114                    lstprop.add(parseFromString(name, part));
115                }
116                prop = (Serializable) lstprop;
117            }
118        }
119        return prop;
120    }
121
122    public Serializable getProperty(String contextPath, String name) {
123
124        Map<String, Serializable> props = getProperties(contextPath);
125        if (props != null) {
126            try {
127                lock.readLock().lock();
128                return props.get(name);
129            } finally {
130                lock.readLock().unlock();
131            }
132        } else {
133            return null;
134        }
135    }
136
137    public Map<String, Serializable> getProperties(String contextPath) {
138
139        contextPath = FilenameUtils.normalizeNoEndSeparator(contextPath);
140
141        try {
142            lock.readLock().lock();
143            Map<String, Serializable> props = collectedMetadata.get(contextPath);
144
145            if (props == null) {
146                File file = new File(contextPath);
147                while (props == null && !StringUtils.isEmpty(file.getParent())) {
148                    file = file.getParentFile();
149                    props = collectedMetadata.get(file.getPath().toString());
150                }
151            }
152
153            if (props != null) {
154                props = Collections.unmodifiableMap(props);
155            }
156            return props;
157        } finally {
158            lock.readLock().unlock();
159        }
160    }
161
162    public void addPropertyFile(File propertyFile) throws IOException {
163
164        Properties mdProperties = new Properties();
165        mdProperties.load(new FileInputStream(propertyFile));
166
167        Map<String, String> stringMap = new HashMap<String, String>();
168        Enumeration names = mdProperties.propertyNames();
169        while (names.hasMoreElements()) {
170            String name = (String) names.nextElement();
171            stringMap.put(name, mdProperties.getProperty(name));
172        }
173        String contextPath = new File(propertyFile.getPath()).getParent();
174        addPropertiesFromStrings(contextPath, stringMap);
175    }
176
177}