package org.aperteworkflow.editor.stepeditor.user;
import com.vaadin.data.Item;
import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.ui.Tree;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import org.aperteworkflow.editor.domain.Permission;
import org.aperteworkflow.editor.stepeditor.TaskConfig;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import pl.net.bluesoft.rnd.util.i18n.I18NSource;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class JSONHandler {
private static final Logger logger = Logger.getLogger(JSONHandler.class.getName());
private static final String WIDGET_ID = "widgetId";
private static final String PRIORITY = "priority";
private static final String PROPERTIES = "properties";
private static final String PERMISSIONS = "permissions";
private static final String STEP_PERMISSIONS = "step-permissions";
private static final String CHILDREN = "children";
private static final String NAME = "name";
public static final String ASSIGNEE = "assignee";
public static final String SWIMLANE = "swimlane";
public static final String CANDIDATE_GROUPS = "candidate_groups";
public static final String DESCRIPTION = "description";
public static final String COMMENTARY = "commentary";
public static class ParsingFailedException extends Exception {
public ParsingFailedException(Exception e) {
super(e);
}
}
public static class WidgetNotFoundException extends Exception {
String widgetItemName;
public WidgetNotFoundException(String widgetItemName) {
this.widgetItemName = widgetItemName;
}
public String getWidgetItemName() {
return widgetItemName;
}
}
private static final ObjectMapper mapper = new ObjectMapper();
public static Map<String, String> loadConfig(HierarchicalContainer hc, WidgetItemInStep rootItem,
String config, Collection<Permission> permissions) throws WidgetNotFoundException, ParsingFailedException {
try {
Map<String, Object> map = mapper.readValue(config, Map.class);
analyzeChildren(map, hc, rootItem);
HashMap<String, String> resultMap = new HashMap<String, String>();
if(map.get(ASSIGNEE) != null){
resultMap.put(ASSIGNEE, map.get(ASSIGNEE).toString());
}
if(map.get(SWIMLANE) != null){
resultMap.put(SWIMLANE, map.get(SWIMLANE).toString());
}
if(map.get(CANDIDATE_GROUPS) != null){
resultMap.put(CANDIDATE_GROUPS, map.get(CANDIDATE_GROUPS).toString());
}
if (map.get(DESCRIPTION) != null) {
resultMap.put(DESCRIPTION, map.get(DESCRIPTION).toString());
}
if (map.get(COMMENTARY) != null) {
resultMap.put(COMMENTARY, decodeAndCreateString( map.get(COMMENTARY).toString()));
}
if (map.containsKey(STEP_PERMISSIONS)) {
Collection<Map> jsonPermissions = (Collection<Map>) map.get(STEP_PERMISSIONS);
for (Map m : jsonPermissions) {
permissions.add(parsePrivilege(m));
}
}
return resultMap;
} catch (JsonParseException e) {
logger.log(Level.SEVERE, "Error loading configuration", e);
throw new ParsingFailedException(e);
} catch (JsonMappingException e) {
logger.log(Level.SEVERE, "Error loading configuration", e);
throw new ParsingFailedException(e);
} catch (IOException e) {
logger.log(Level.SEVERE, "Error loading configuration", e);
throw new ParsingFailedException(e);
}
}
public static String decodeAndCreateString(String stringToDecode){
return new String(Base64.decodeBase64(stringToDecode.getBytes()));
}
private static void analyzeChildren(Map<String, Object> map, HierarchicalContainer hc, WidgetItemInStep rootItem) throws WidgetNotFoundException {
Collection<Map<String, Object>> children = (Collection<Map<String, Object>>) map.get(CHILDREN);
if (children != null) {
for (Map<String, Object> node : children) {
WidgetItemInStep newItem = analyzeNode(node, hc, rootItem);
analyzeChildren(node, hc, newItem);
}
}
}
private static WidgetItemInStep analyzeNode(Map<String, Object> node, HierarchicalContainer hc, WidgetItemInStep rootItem) throws WidgetNotFoundException {
String widgetItemName = (String) node.get(WIDGET_ID);
WidgetItem widgetItem = WidgetItem.getWidgetItem(widgetItemName);
if (widgetItem == null) {
throw new WidgetNotFoundException(widgetItemName);
}
final WidgetItemInStep item = new WidgetItemInStep(widgetItem);
Map<String, Object> properties = (Map<String, Object>) node.get(PROPERTIES);
if (properties != null) {
for (Map.Entry<String, Object> e : properties.entrySet()) {
for (Property<?> property : item.getProperties()) {
if (property.getPropertyId().equals(e.getKey())) {
property.setValue(new String(Base64.decodeBase64(e.getValue().toString())));
}
}
}
}
try {
Collection<Map> jsonPermissions = (Collection<Map>) node.get(PERMISSIONS);
if (jsonPermissions != null) {
List<Permission> permissions = new ArrayList<Permission>();
for (Map m : jsonPermissions) {
permissions.add(parsePrivilege(m));
}
item.setPermissions(new ArrayList<Permission>(new LinkedHashSet<Permission>(permissions)));
}
} catch (ClassCastException e) { //TODO removeme, I exist only for backwards dev compatibility
//nothing
}
Item newItem = hc.addItem(item);
newItem.getItemProperty(NAME).setValue(widgetItem.getName());
hc.setParent(item, rootItem);
hc.setChildrenAllowed(item, widgetItem.getChildrenAllowed());
return item;
}
private static Permission parsePrivilege(Map m) {
Permission p = new Permission();
p.setPrivilegeName((String) m.get("privilegeName"));
p.setRoleName((String) m.get("roleName"));
return p;
}
private static Map<String, Object> collectNode(final Tree tree, Object node, Integer priority) {
Map<String, Object> map = new HashMap<String, Object>();
final WidgetItemInStep widgetItemInStep = (WidgetItemInStep) node;
Map<String, Object> propertiesMap = new HashMap<String, Object>();
if (widgetItemInStep.hasProperties()) {
for (Property<?> property : widgetItemInStep.getProperties()) {
if (property.getValue() != null) {
String encoded = Base64.encodeBase64URLSafeString(property.getValue().toString().getBytes());
propertiesMap.put(property.getPropertyId(), encoded);
}
}
}
map.put(WIDGET_ID, widgetItemInStep.getWidgetItem().getWidgetId());
map.put(PRIORITY, priority);
if (!propertiesMap.isEmpty()) {
map.put(PROPERTIES, propertiesMap);
}
if (!widgetItemInStep.getPermissions().isEmpty()) {
map.put(PERMISSIONS, widgetItemInStep.getPermissions());
}
if (tree.hasChildren(node)) {
map.put(CHILDREN, CollectionUtils.collect(tree.getChildren(node), new Transformer() {
private Integer priorityCounter = 1;
@Override
public Object transform(Object node) {
priorityCounter++;
return collectNode(tree, node, priorityCounter);
}
}));
}
return map;
}
protected static String dumpTreeToJSON(Tree tree, WidgetItemInStep rootItem, Object assignee,
Object candidateGroups, Object swimlane, String stepName,
Object description, Object commentary,
Collection<Permission> permissions) {
I18NSource messages = I18NSource.ThreadUtil.getThreadI18nSource();
TaskConfig tc = new TaskConfig();
tc.setTaskName(stepName);
Map<String, Object> treeMap = collectNode(tree, rootItem, 1);
if (assignee != null) {
treeMap.put(ASSIGNEE, assignee);
}
if (candidateGroups != null) {
treeMap.put(CANDIDATE_GROUPS, candidateGroups);
}
if (swimlane != null) {
treeMap.put(SWIMLANE, swimlane);
}
if (permissions != null) {
treeMap.put(STEP_PERMISSIONS, permissions);
}
if (description != null) {
treeMap.put(DESCRIPTION,description);
}
if (commentary != null) {
treeMap.put(COMMENTARY, encodeString(commentary));
}
tc.setParams(treeMap);
try {
return mapper.writeValueAsString(tc);
} catch (JsonGenerationException e) {
logger.log(Level.SEVERE, "Error dumping tree", e);
} catch (JsonMappingException e) {
logger.log(Level.SEVERE, "Error dumping tree", e);
} catch (IOException e) {
logger.log(Level.SEVERE, "Error dumping tree", e);
}
return messages.getMessage("dump.failed");
}
public static String encodeString(Object objectToConvert){
byte[] bytes = objectToConvert.toString().getBytes();
return Base64.encodeBase64URLSafeString(bytes);
}
}