
com.adobe.aemds.guide.xfa.XFAJSONTransformer Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2014 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.adobe.aemds.guide.xfa;
import com.adobe.aemds.guide.service.GuideException;
import com.adobe.aemds.guide.utils.GuideConstants;
import com.day.cq.commons.jcr.JcrConstants;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.StringWriter;
import java.util.*;
/**
* @pad.exclude Exclude from Published API.
*/
public class XFAJSONTransformer {
private Logger logger = LoggerFactory.getLogger(XFAJSONTransformer.class);
private static List panelCandidates =
Arrays.asList(new String[]{"area", "subform", "subformSet"});
private static List leafCandidates =
Arrays.asList(new String[]{"draw", "exclGroup", "field"});
private static List unsupportedUiTypes = Arrays.asList(new String[]{
"barcode", "exObject", "signature"
});
private static List unsupportedValueTypes = Arrays.asList(new String[]{
"arc", "line", "rectangle"
});
private JSONObject xfaJson;
private XFAJSONWriter jsonWriter;
private StringWriter stringWriter;
private Hashtable xfaObjects;
private XFAJSONTransformerUtil transformUtil;
//Used to manage jcr path element for same named field
private Map currentContainerChildren = new HashMap();
private ResourceResolver resourceResolver = null;
public XFAJSONTransformer(JSONObject xfaJson) {
this(xfaJson, null, "");
}
public XFAJSONTransformer(JSONObject xfaJson,ResourceResolver resourceResolver, String xfaPath) {
this.xfaJson = xfaJson;
this.stringWriter = new StringWriter();
this.jsonWriter = new XFAJSONWriter(this.stringWriter);
transformUtil = new XFAJSONTransformerUtil(resourceResolver, xfaPath);
}
public XFAJSONTransformer(JSONObject xfaJson, boolean saveObjects, ResourceResolver resourceResolver, String xfaPath) {
this(xfaJson, resourceResolver, xfaPath);
xfaObjects = new Hashtable();
}
public boolean acceptObject(final JSONObject jsonObject) throws Exception {
String childType = jsonObject.getString("_class");
if (!(panelCandidates.contains(childType) || leafCandidates.contains(childType))) {
return false;
}
if (leafCandidates.contains(childType) && !this.acceptLeaf(jsonObject)) {
return false;
}
return true;
}
public String transform() {
try {
JSONObject rootSubformJson = (JSONObject) transformUtil.getOrElse(this.xfaJson,
"form.subform", null, false);
String rootSubformName = transformUtil.getOrGenerateName(rootSubformJson);
jsonWriter.startObject(null)
.startObject(rootSubformName);
transformContainer(rootSubformJson);
jsonWriter.completeObject(rootSubformName)
.completeObject(null);
return this.stringWriter.toString();
} catch (Exception e) {
logger.error("Error in transforming xfa json:" + e.getMessage(), e);
throw new GuideException(e);
}
}
private void transformChildren(JSONObject containerJson, boolean isChildOfTable) throws Exception{
if (containerJson.has("children") && containerJson.get("children") instanceof JSONArray) {
Map oldChildMap = this.currentContainerChildren;
this.currentContainerChildren = new HashMap();
try {
JSONObject lastInstanceManager = null;
jsonWriter.startObject("items");
JSONArray containerChildren = containerJson.getJSONArray("children");
for (int i = 0; i < containerChildren.length(); i++) {
JSONObject childJson = containerChildren.getJSONObject(i);
String childType = childJson.getString("_class");
if(!"subform".equals(childType)){
// InstanceManager should be reset if current child is not subform
lastInstanceManager = null;
}
if("instanceManager".equals(childType)){
//InstanceManager should be transformed with it's corresponding subform.
lastInstanceManager = childJson;
continue;
}
if(acceptObject(childJson)) {
String childName = transformUtil.getOrGenerateName(childJson);
int childIndex = -1;
if (currentContainerChildren.containsKey(childName)) {
childIndex = currentContainerChildren.get(childName);
}
childIndex++;
currentContainerChildren.put(childName, childIndex);
childName = childName + ((childIndex == 0) ? "" : childIndex);
jsonWriter.startObject(childName);
if (panelCandidates.contains(childType)) {
// even header of XDP has "layout" property as row
// todo: since header is optional in XDP, how to handle that ?
if(isChildOfTable && childJson.has("layout") && "row".equals((String)childJson.get("layout"))){
transformTableChild(childJson);
} else {
transformContainer(childJson);
}
if(lastInstanceManager!=null){
/*
* Currently we do not support explicit initial count in panel. Though Guide runtime would automatically handle for XFA Guides.
*/
if(lastInstanceManager.has("min")){
jsonWriter.key("minOccur").value(lastInstanceManager.getInt("min"));
}
if(lastInstanceManager.has("max")){
jsonWriter.key("maxOccur").value(lastInstanceManager.getInt("max"));
}
}
} else if ("exclGroup".equals(childType)) {
transformExclGroup(childJson, isChildOfTable);
} else if ("draw".equals(childType)) {
//Need to handle rich text encoding before enabling below.
transformDraw(childJson, isChildOfTable);
} else {
transformField(childJson, isChildOfTable);
}
jsonWriter.completeObject(childName);
}
}
jsonWriter.completeObject("items");
} finally {
this.currentContainerChildren = oldChildMap;
}
}
}
private void transformContainer(final JSONObject containerJson, boolean isJsonTable) throws Exception {
if(isJsonTable){
// check if it is table, then transform it into table
transformTable(containerJson);
} else {
transformPanel(containerJson);
}
jsonWriter.startObject("layout");
Hashtable hash = transformUtil.getLayoutProperties(null, isJsonTable);
jsonWriter.writeProperties(hash);
jsonWriter.completeObject("layout");
transformChildren(containerJson, isJsonTable);
}
/**
* Checks if the given XDP table is supported by adaptive forms
*
* In adaptive forms, we don't support following:
* a) Table with multiple headers
* b) Table with no headers
* c) Table within table
*
* @param containerJson
* @return
* @throws Exception
*/
public boolean checkIfSupportedTable(final JSONObject containerJson) throws Exception {
return checkIfSupportedTable(containerJson, 0);
}
private boolean checkIfSupportedTable(final JSONObject containerJson, int tableHeaderCount) throws Exception {
if (containerJson.has("children") && containerJson.get("children") instanceof JSONArray) {
JSONArray containerChildren = containerJson.getJSONArray("children");
for (int i = 0; i < containerChildren.length(); i++) {
JSONObject childJson = containerChildren.getJSONObject(i);
String childType = childJson.getString("_class");
if(acceptObject(childJson)) {
if (panelCandidates.contains(childType)) {
// even header of XDP has "layout" property as row
if(childJson.has("layout") && "table".equals((String)childJson.get("layout"))){
return false;
} else {
if(tableHeaderCount == 0){
// this must be a table header always
if(checkIfContainerIsTableHeader(childJson)){
boolean isValidTable = checkIfSupportedTable(childJson, tableHeaderCount++);
if (!isValidTable) {
return false;
}
} else {
// if first child is not header, we don't support tables without headers
return false;
}
} else {
// If the header count in table present in XDP is greater than 1, exit
if(checkIfContainerIsTableHeader(childJson)){
// we don't support multiple headers
return false;
}
boolean isValidTable = checkIfSupportedTable(childJson, tableHeaderCount);
if(!isValidTable){
// if there is table inside table, we don't support
return false;
}
}
}
}
}
}
}
return true;
}
private void transformContainer(final JSONObject containerJson) throws Exception {
// check if the container is a table
boolean bIsJsonTable = false;
if(containerJson.has("layout")){
if(containerJson.get("layout") instanceof String) {
String layout = (String)containerJson.get("layout");
if(layout != null && layout.length() > 0 && "table".equals(layout)){
bIsJsonTable = checkIfSupportedTable(containerJson, 0);
}
}
}
transformContainer(containerJson, bIsJsonTable);
}
/**
* Checks if the JSON is a table header
* This uses assist class to find the same
* @param containerJson
* @return
* @throws Exception
*/
private boolean checkIfContainerIsTableHeader(final JSONObject containerJson) throws Exception{
boolean isHeader = false;
JSONArray containerChildren = containerJson.getJSONArray("children");
for (int i = 0; i < containerChildren.length(); i++) {
JSONObject childJson = containerChildren.getJSONObject(i);
String childType = childJson.getString("_class");
if("assist".equals(childType)) {
isHeader = "TH".equals(childJson.getString("role"));
break;
}
}
return isHeader;
}
/**
* Transforms the table child element from the container json into adaptive forms table
* @param containerJson
* @throws Exception
*/
private void transformTableChild(final JSONObject containerJson) throws Exception {
// todo: check if table child also is a table
// in that case: fallback to panel hierarchy
Hashtable hash = transformUtil.getCommonProperties(null, containerJson);
boolean bIsHeader = checkIfContainerIsTableHeader(containerJson);
// check if the current container is a header using
if(bIsHeader){
hash.put(GuideConstants.SLING_RESOURCE_TYPE, GuideConstants.RT_TABLE_HEADER);
} else {
hash.put(GuideConstants.SLING_RESOURCE_TYPE, GuideConstants.RT_TABLE_ROW);
}
hash.put(GuideConstants.ELEMENT_PROPERTY_NODECLASS, GuideConstants.GUIDE_TABLE_ROW);
if(hash.containsKey("bindRef")) {
transformObjectFromHash(hash);
} else {
logger.warn("XFA Element for: "+hash.get(JcrConstants.JCR_TITLE)+" does not contain bindRef.");
}
hash.clear();
jsonWriter.startObject("layout");
String layoutResourceType = null;
// Based on the index set the layout
if(bIsHeader){
layoutResourceType = GuideConstants.LAYOUT_TABLE_HEADER_LAYOUT;
} else {
layoutResourceType = GuideConstants.LAYOUT_TABLE_ROW_LAYOUT;
}
hash.put(JcrConstants.JCR_PRIMARYTYPE, GuideConstants.NT_UNSTRUCTURED);
hash.put(GuideConstants.SLING_RESOURCE_TYPE, layoutResourceType);
jsonWriter.writeProperties(hash);
jsonWriter.completeObject("layout");
transformChildren(containerJson, true);
}
private String getJsonStringFromHash(Hashtable hash) {
StringWriter writer = new StringWriter();
XFAJSONWriter jsonWriter = new XFAJSONWriter(writer);
jsonWriter.startObject(null);
jsonWriter.writeProperties(hash);
jsonWriter.completeObject(null);
return writer.toString();
}
/**
* Transforms XDP Table into adaptive forms Table
*
* @param tableJson
* @throws Exception
*/
public void transformTable(JSONObject tableJson) throws Exception {
Hashtable hash = transformUtil.getCommonProperties(null, tableJson);
hash = transformUtil.getTableProperties(hash);
if(hash.containsKey("bindRef")) {
transformObjectFromHash(hash);
} else {
logger.warn("XFA Element for: "+hash.get(JcrConstants.JCR_TITLE)+" does not contain bindRef.");
}
}
private void transformPanel(JSONObject panelJson) throws Exception {
Hashtable hash = transformUtil.getCommonProperties(null, panelJson);
hash = transformUtil.getPanelProperties(hash);
if(hash.containsKey("bindRef")) {
transformObjectFromHash(hash);
} else {
logger.warn("XFA Element for: "+hash.get(JcrConstants.JCR_TITLE)+" does not contain bindRef.");
}
}
private void transformObjectFromHash(Hashtable hash) {
String jsonString = getJsonStringFromHash(hash);
if(xfaObjects != null) {
xfaObjects.put((String)hash.get("bindRef"), jsonString);
}
hash.put("xfajson", jsonString);
jsonWriter.writeProperties(hash);
}
private void transformField(JSONObject fieldJson, boolean isChildOfTable) throws Exception {
Hashtable input = transformUtil.getFieldProperties(null, fieldJson);
// check if child of table and has colSpan then add it to hash
if(isChildOfTable && fieldJson.has("colSpan")){
input.put("colspan", fieldJson.get("colSpan"));
}
transformObjectFromHash(input);
}
private void transformDraw(JSONObject drawJson, boolean isChildOfTable) throws Exception {
Hashtable input = transformUtil.getDrawProperties(null, drawJson);
if(isChildOfTable && drawJson.has("colSpan")){
input.put("colspan", drawJson.get("colSpan"));
}
transformObjectFromHash(input);
}
private void transformExclGroup(JSONObject exclGroupJson, boolean isChildOfTable) throws Exception {
Hashtable input = transformUtil.getExclGroupProperties(null, exclGroupJson);
if(isChildOfTable && exclGroupJson.has("colSpan")){
input.put("colspan", exclGroupJson.get("colSpan"));
}
transformObjectFromHash(input);
}
public final Hashtable getXFAObjects() {
return xfaObjects;
}
public boolean acceptLeaf(JSONObject leafJson) throws Exception {
String childType = leafJson.getString("_class");
if ("draw".equals(childType) || "field".equals(childType)) {
String fieldUiType = (String) transformUtil.getOrElse(leafJson, "ui.oneOfChild._class", null, true);
if (unsupportedUiTypes.contains(fieldUiType)) {
return false; //Not supporting above fields for now
} else if ("defaultUi".equals(fieldUiType)) {
String valueType = (String) transformUtil.getOrElse(leafJson, "value.oneOfChild._class",
null, true);
if (unsupportedValueTypes.contains(valueType)) {
return false; //Unsupported draw
}
}
return true;
} else if ("exclGroup".equals(childType)) {
return true;
}
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy