package act.inject.param; /*- * #%L * ACT Framework * %% * Copyright (C) 2014 - 2017 ActFramework * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import act.util.ActContext; import org.osgl.logging.LogManager; import org.osgl.logging.Logger; import org.osgl.util.S; import java.util.*; class ParamTree { private static final Logger LOGGER = LogManager.get(ParamTree.class); private Map<ParamKey, ParamTreeNode> allNodes = new HashMap<>(); void build(ActContext context) { Set<String> paramKeys = context.paramKeys(); for (String key : paramKeys) { String[] vals = context.paramVals(key); buildNode(key, vals); } } private void buildNode(String rawKey, String[] vals) { ParamKey key = ParamKey.of(parseRawParamKey(rawKey)); ParamTreeNode node; int len = vals.length; if (len == 0) { return; } if (len > 1) { node = ParamTreeNode.list(key); for (int i = 0; i < vals.length; ++i) { ParamTreeNode leafNode = ParamTreeNode.leaf(key, vals[i]); node.addListItem(leafNode); } } else { node = ParamTreeNode.leaf(key, vals[0]); } allNodes.put(key, node); len = key.size(); if (len == 1) { return; } ensureParent(key, node); } ParamTreeNode node(ParamKey key) { return allNodes.get(key); } private void ensureParent(ParamKey childKey, ParamTreeNode child) { ParamKey parentKey = childKey.parent(); if (null == parentKey) { return; } ParamTreeNode parent = allNodes.get(parentKey); if (null == parent) { parent = ParamTreeNode.map(parentKey); allNodes.put(parentKey, parent); } parent.addChild(childKey.name(), child); int len = parentKey.size(); if (len > 1) { ensureParent(parentKey, parent); } } /* * Parse string like `foo[bar][0][id]` into String array * `foo, bar, 0, id`. * * It shall also support dot notation: `foo.bar.0.id`, or mixed: * `foo.bar[0].id`. However things like `foo[0.05]` must be interpreted into * `foo, 0.05` instead of `foo, 0, 05` */ private static String[] parseRawParamKey(String rawKey) { List<String> list = new ArrayList<>(); int len = rawKey.length(); boolean inSquare = false; S.Buffer token = S.buffer(); for (int i = 0; i < len; ++i) { char c = rawKey.charAt(i); switch (c) { case '.': if (inSquare) { token.append(c); } else { addTokenToList(list, token); } continue; case ']': inSquare = false; addTokenToList(list, token); continue; case '[': inSquare = true; addTokenToList(list, token); continue; default: token.append(c); } } addTokenToList(list, token); return list.toArray(new String[list.size()]); } private static void addTokenToList(List<String> list, S.Buffer token) { String s = token.toString(); if (S.notEmpty(s)) { list.add(s); } else { LOGGER.warn("empty index encountered"); } token.delete(0, s.length() + 1); } }