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