package io.cattle.platform.object.serialization.impl;
import io.cattle.platform.json.JsonMapper;
import io.cattle.platform.object.ObjectManager;
import io.cattle.platform.object.meta.ObjectMetaDataManager;
import io.cattle.platform.object.serialization.ObjectSerializer;
import io.cattle.platform.object.serialization.ObjectSerializerFactory;
import io.cattle.platform.object.serialization.ObjectTypeSerializerPostProcessor;
import io.cattle.platform.util.type.CollectionUtils;
import io.cattle.platform.util.type.InitializationTask;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.inject.Inject;
public class DefaultObjectSerializerFactoryImpl implements ObjectSerializerFactory, InitializationTask {
private static final Pattern GOOD_CHARS = Pattern.compile("[a-z0-9]", Pattern.CASE_INSENSITIVE);
JsonMapper jsonMapper;
ObjectManager objectManager;
ObjectMetaDataManager metaDataManager;
Map<String, List<ObjectTypeSerializerPostProcessor>> postProcessorsMap = new HashMap<String, List<ObjectTypeSerializerPostProcessor>>();
List<ObjectTypeSerializerPostProcessor> postProcessors;
@Override
public ObjectSerializer compile(String type, String expression) {
Action action = parseAction(type, expression);
DefaultObjectSerializerImpl result = new DefaultObjectSerializerImpl(jsonMapper, objectManager, metaDataManager, postProcessorsMap, action, expression);
result.serialize(null);
return result;
}
@Override
public void start() {
for (ObjectTypeSerializerPostProcessor postProcessor : postProcessors) {
for (String type : postProcessor.getTypes()) {
CollectionUtils.addToMap(postProcessorsMap, type, postProcessor, ArrayList.class);
}
}
}
protected Action parseAction(String type, String expression) {
/* Should use antlr if this gets too complicated */
Context c = new Context();
for (int i = 0; i < expression.length(); i++) {
char current = expression.charAt(i);
switch (current) {
case '|':
case ',':
c = endWord(c, current);
c.done = false;
break;
case '.':
c.dotStart = true;
c = c.push();
break;
case '[':
c = c.push();
break;
case ']':
c = endWord(c, current);
c = c.pop(expression);
break;
default:
if (!GOOD_CHARS.matcher(Character.toString(current)).matches() || c.done) {
throw new IllegalArgumentException("Bad character [" + current + "] found in [" + expression + "]");
}
c.currentWord.append(current);
break;
}
}
if (c.currentWord.length() > 0) {
c = endWord(c, ' ');
}
if (c.parent != null) {
throw new IllegalStateException("Missing closing ']' in [" + expression + "]");
}
return new Action(type, c.currentActions);
}
protected static Context endWord(Context c, char current) {
if (c.currentWord.length() == 0 && c.currentAction.getName() == null) {
throw new IllegalStateException("got [" + current + "] but there is no word before it");
}
c.currentAction.setName(c.currentWord.toString());
c.currentActions.add(c.currentAction);
c.currentAction = new Action();
c.currentWord.setLength(0);
if (current != '.') {
if (c.parent != null && c.parent.dotStart) {
return endWord(c.parent, current);
}
}
return c;
}
private static final class Context {
Context parent = null;
List<Action> currentActions = new ArrayList<Action>();
Action currentAction = new Action();
StringBuilder currentWord = new StringBuilder();
boolean dotStart = false;
boolean done = false;
Context push() {
Context child = new Context();
child.parent = this;
currentAction.setChildren(child.currentActions);
this.done = true;
return child;
}
Context pop(String expression) {
if (parent == null) {
throw new IllegalStateException("To many closing braces in [" + expression + "]");
}
return parent;
}
@Override
public String toString() {
Context current = this;
while (current.parent != null) {
current = current.parent;
}
if (current.currentWord.length() > 0) {
List<Action> actions = new ArrayList<Action>(current.currentActions);
actions.add(new Action(current.currentWord.toString() + "*", current.currentAction.getChildren()));
return actions.toString();
} else {
return current.currentActions.toString();
}
}
}
public JsonMapper getJsonMapper() {
return jsonMapper;
}
@Inject
public void setJsonMapper(JsonMapper jsonMapper) {
this.jsonMapper = jsonMapper;
}
public ObjectManager getObjectManager() {
return objectManager;
}
@Inject
public void setObjectManager(ObjectManager objectManager) {
this.objectManager = objectManager;
}
public ObjectMetaDataManager getMetaDataManager() {
return metaDataManager;
}
@Inject
public void setMetaDataManager(ObjectMetaDataManager metaDataManager) {
this.metaDataManager = metaDataManager;
}
public List<ObjectTypeSerializerPostProcessor> getPostProcessors() {
return postProcessors;
}
@Inject
public void setPostProcessors(List<ObjectTypeSerializerPostProcessor> postProcessors) {
this.postProcessors = postProcessors;
}
}