act.inject.param.ParamTree Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of act Show documentation
Show all versions of act Show documentation
The ACT full stack MVC framework
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.app.ActionContext;
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 allNodes = new HashMap<>();
private ParamTreeNode rootNode;
void build(ActContext context) {
Set 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, ActContext context) {
ParamTreeNode node = allNodes.get(key);
if (null == node && context.isAllowIgnoreParamNamespace()) {
key = key.withoutNamespace();
if (null == key) {
// take out URL variable values.
if (context instanceof ActionContext) {
ActionContext actionContext = (ActionContext) context;
Map nonUrlPathVars = new HashMap<>();
for (Map.Entry entry : allNodes.entrySet()) {
if (!actionContext.isPathVar(entry.getKey().name())) {
nonUrlPathVars.put(entry.getKey(), entry.getValue());
}
}
Map copy = allNodes;
allNodes = nonUrlPathVars;
node = asRootNode();
allNodes = copy;
return node;
}
if (null == rootNode) {
rootNode = asRootNode();
}
node = rootNode;
} else {
node = allNodes.get(key);
}
}
return node;
}
private ParamTreeNode asRootNode() {
ParamTreeNode root = ParamTreeNode.map(ParamKey.ROOT_KEY);
for (Map.Entry entry : allNodes.entrySet()) {
ParamKey key = entry.getKey();
if (key.size() > 1) {
continue;
}
root.addChild(key.name(), entry.getValue());
}
return root;
}
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 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 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);
}
}