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);
}
}