001/*
002 * (C) Copyright 2016 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 *     Florent Guillaume
018 *     Kevin Leturc
019 */
020package org.nuxeo.ecm.core.storage.dbs;
021
022import static org.nuxeo.ecm.core.storage.dbs.DBSDocument.KEY_PREFIX;
023
024import java.io.Serializable;
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.List;
028import java.util.Map;
029import java.util.Map.Entry;
030
031import org.nuxeo.ecm.core.storage.State;
032
033/**
034 * Function to flatten and convert {@link State} into NXQL {@link Map}<{@link String}, {@link Serializable}>.
035 *
036 * @since 8.3
037 */
038public class DBSStateFlattener {
039
040    protected final Map<String, String> keyMappings;
041
042    public DBSStateFlattener() {
043        this.keyMappings = Collections.emptyMap();
044    }
045
046    public DBSStateFlattener(Map<String, String> keyMappings) {
047        this.keyMappings = keyMappings != null ? keyMappings : Collections.emptyMap();
048    }
049
050    /**
051     * Flattens with optional property key mappings.
052     * @param state state
053     * @return flattened result
054     * @since 9.3
055     */
056    public Map<String, Serializable> flatten(State state) {
057        Map<String, Serializable> map = new HashMap<>();
058        flatten(map, state, null);
059        return map;
060    }
061
062    protected void flatten(Map<String, Serializable> map, State state, String prefix) {
063        for (Entry<String, Serializable> en : state.entrySet()) {
064            String key = en.getKey();
065            Serializable value = en.getValue();
066            String name;
067            String realName = keyMappings.get(key);
068            if (realName != null) {
069                name = realName;
070            } else if (key.startsWith(KEY_PREFIX)) {
071                name = DBSSession.convToNXQL(key);
072                if (name == null) {
073                    // present in state but not returned to caller
074                    continue;
075                }
076            } else {
077                name = key;
078            }
079            name = prefix == null ? name : prefix + name;
080            if (value instanceof State) {
081                flatten(map, (State) value, name + '/');
082            } else if (value instanceof List) {
083                String nameSlash = name + '/';
084                int i = 0;
085                for (Object v : (List<?>) value) {
086                    if (v instanceof State) {
087                        flatten(map, (State) v, nameSlash + i + '/');
088                    } else {
089                        map.put(nameSlash + i, (Serializable) v);
090                    }
091                    i++;
092                }
093            } else if (value instanceof Object[]) {
094                String nameSlash = name + '/';
095                int i = 0;
096                for (Object v : (Object[]) value) {
097                    map.put(nameSlash + i, (Serializable) v);
098                    i++;
099                }
100            } else {
101                map.put(name, value);
102            }
103        }
104    }
105
106}