package fr.eyal.datalib.generator; import java.math.BigInteger; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Stack; import org.eclipse.emf.common.util.EList; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import fr.eyal.lib.datalib.genmodel.android.datalib.DataLibProject; import fr.eyal.lib.datalib.genmodel.android.datalib.DatalibFactory; import fr.eyal.lib.datalib.genmodel.android.datalib.DatalibPackage; import fr.eyal.lib.datalib.genmodel.android.datalib.WebService; import fr.eyal.lib.datalib.genmodel.android.datalib.content.DataLibOption; import fr.eyal.lib.datalib.genmodel.android.datalib.content.HttpMethod; import fr.eyal.lib.datalib.genmodel.android.datalib.content.ParameterType; import fr.eyal.lib.datalib.genmodel.android.datalib.content.ParseType; import fr.eyal.lib.datalib.genmodel.android.datalib.model.BusinessObject; import fr.eyal.lib.datalib.genmodel.android.datalib.model.BusinessObjectDAO; import fr.eyal.lib.datalib.genmodel.android.datalib.model.Field; import fr.eyal.lib.datalib.genmodel.android.datalib.model.FieldBusinessObject; import fr.eyal.lib.datalib.genmodel.android.datalib.model.ModelFactory; import fr.eyal.lib.datalib.genmodel.android.datalib.model.ModelPackage; import fr.eyal.lib.datalib.genmodel.android.datalib.model.Parameter; import fr.eyal.lib.datalib.genmodel.android.datalib.model.ResponseBusinessObject; public class DataLibGeneratorParser extends DefaultHandler { private static final String TAG = DataLibGeneratorParser.class.getSimpleName(); public static final int UNKNOWN = -1; //Content tags private static final int PROJECT = 0; private static final int WEBSERVICE = 1; private static final int CONFIG = 2; private static final int HTTP_METHOD = 3; private static final int PARSE_TYPE = 4; private static final int OPTIONS = 5; private static final int PARAMETERS = 6; private static final int CONTENT = 7; private static final int OPTIONS_OPTION = 8; private int mState = UNKNOWN; private final StringBuilder mBuilder = new StringBuilder(); private DataLibProject project; private WebService webservice; String name = DataLibConfig.DEFAUT_PROJECT_NAME; String packageName = DataLibConfig.DEFAUT_PROJECT_PACKAGE; String authority = DataLibConfig.DEFAUT_PROJECT_AUTHORITY; String databaseName = DataLibConfig.DEFAUT_PROJECT_DATABASE_NAME; String databaseVersion = DataLibConfig.DEFAUT_PROJECT_DATABASE_VERSION; DatalibFactory factory; ModelFactory modelFactory; BusinessObject parent; //the current parent of the node BusinessObject bo; //the current business object where to include a new node Field field = null; //the current field Field fieldXML = null; //the current xmlField boolean isFillingField = false; //tells whether we are filling a Field or not Field tempField; // ArrayList<String> javaNameList = new ArrayList<String>(); //the list of the member variables contained inside the current BusinessObject Stack<String> javaTagStack = new Stack<>(); //stack of names for the current BusinessObject ArrayList<String> prefixList = new ArrayList<String>(); String prefixName = ""; //the prefix to paste for the current node's name String responseTagName; //the first content node's tag name boolean isResponseField = false; //tells if we are on the ResponseBusinessObject level and the content does not still has a contentField Attributes mCurrentAttributes; boolean cached = DataLibConfig.DEFAUT_WEBSERVICE_CACHED; int contentLevel = 0; long parseId = 0; public DataLibGeneratorParser() { //initialize the model DatalibPackage.eINSTANCE.eClass(); ModelPackage.eINSTANCE.eClass(); //retrieve the default factory singleton factory = DatalibFactory.eINSTANCE; modelFactory = ModelFactory.eINSTANCE; System.out.println("Creation of the model..."); } @Override public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException { // String attString = ""; // for (int i = 0; i < attributes.getLength(); i++) { // attString += " - " + attributes.getQName(i); // } for (int i = 0; i < contentLevel; i++) { System.out.print("-"); } System.out.println(qName); mBuilder.setLength(0); mCurrentAttributes = attributes; switch (mState) { case UNKNOWN: if (qName.equals(DataLibLabels.XML_PROJECT)) { mState = PROJECT; name = attributes.getValue(DataLibLabels.XML_NAME); packageName = attributes.getValue(DataLibLabels.XML_PACKAGE); authority = attributes.getValue(DataLibLabels.XML_AUTHORITY); databaseName = attributes.getValue(DataLibLabels.XML_DATABASE_NAME); databaseVersion = attributes.getValue(DataLibLabels.XML_DATABASE_VERSION); if(name == null) name = DataLibConfig.DEFAUT_PROJECT_NAME; if(packageName == null) packageName = DataLibConfig.DEFAUT_PROJECT_PACKAGE; if(authority == null) authority = DataLibConfig.DEFAUT_PROJECT_AUTHORITY; if(databaseName == null) databaseName = DataLibConfig.DEFAUT_PROJECT_DATABASE_NAME; if(databaseVersion == null) databaseVersion = DataLibConfig.DEFAUT_PROJECT_DATABASE_VERSION; project = DataLibGenerator.createProject(factory, authority, databaseName, databaseVersion, name, packageName); } break; case PROJECT: if (qName.equals(DataLibLabels.XML_WEBSERVICE)) { mState = WEBSERVICE; //we clear the webservice values cached = DataLibConfig.DEFAUT_WEBSERVICE_CACHED; contentLevel = 0; // parseId = 0; HttpMethod httpMethod = getHttpMethod(attributes.getValue(DataLibLabels.XML_HTTP_METHOD)); ParseType parseType = getParseType(attributes.getValue(DataLibLabels.XML_PARSE_TYPE)); String url = attributes.getValue(DataLibLabels.XML_URL); if(url == null) throw new SAXException("'"+DataLibLabels.XML_URL+"' attributes is mandatory for each "+DataLibLabels.XML_WEBSERVICE+" tag. ou must provide the URL reference of the webservice"); name = attributes.getValue(DataLibLabels.XML_NAME); webservice = factory.createWebService(); webservice.setCached(true); webservice.setMethod(httpMethod); webservice.setPackage(packageName); webservice.setParseType(parseType); webservice.setUrl(url); webservice.setName(name); project.getWebservices().add(webservice); ResponseBusinessObject response; String javaTag = getJavaTag(name); String javaName = name; //we create the response depending on the cache status if(cached){ response = modelFactory.createResponseBusinessObjectDAO(); DataLibGenerator.fillBusinessObjectDAO((BusinessObjectDAO) response, name, packageName, new BigInteger(""+parseId), qName, javaName, javaTag, null, null, null, null, project); } else { response = modelFactory.createResponseBusinessObject(); DataLibGenerator.fillBusinessObject(response, name, packageName, new BigInteger(""+parseId), qName, javaName, javaTag, null, null, null, null); } parseId++; //we increment the parseId counter //we add the content response to the webservice webservice.setContentResponse((ResponseBusinessObject) response); parent = response; //we set the response as the node's parent bo = response; //we set the response as the current business object to fill } break; case WEBSERVICE: case CONTENT: if (qName.equals(DataLibLabels.XML_CONFIG)) { mState = CONFIG; } else { //if we are on a content tag mState = CONTENT; //we get the name String name = attributes.getValue(DataLibLabels.XML_NAME); if(name == null) name = qName; javaTagStack.push(qName); String javaTag = getJavaTag(qName); //we check if the node is multiple. If it is we create a new child for the parent boolean multiple = Boolean.parseBoolean(attributes.getValue(DataLibLabels.XML_MULTIPLE)); //if we are in the content response (first node of the content) if(contentLevel == 0){ //we tell that we are on the response level isResponseField = true; String javaName = getJavaName(name); //we manage the attributes linking processBOAttributes(attributes, bo, null); prefixList.clear(); prefixName = name; // we declare the prefix name responseTagName = qName; //we set the response tag name //we create and add the new XML node if(multiple) tempField = DataLibGenerator.createFieldBusinessObject(modelFactory, name, null, "", "", qName, javaName, javaTag, new BigInteger(""+parseId), null, parent, null, bo, null); else tempField = DataLibGenerator.createField(modelFactory, name, null, "", "", qName, javaName, javaTag, new BigInteger(""+parseId), null, parent, null); parseId++; ((ResponseBusinessObject)bo).getXmlContentFields().add(tempField); fieldXML = tempField; } else { //if we are on the rest of the content //We tells that we are out on the response level isResponseField = false; //if the tag is multiple, we add a new content level if(multiple){ String javaName = getJavaName(name); //we create the BusinessObject depending on the cache status if(cached){ bo = modelFactory.createBusinessObjectDAO(); DataLibGenerator.fillBusinessObjectDAO((BusinessObjectDAO) bo, name, packageName, new BigInteger(""+parseId), qName, javaName, javaTag, null, null, null,null, project); } else { bo = modelFactory.createBusinessObject(); DataLibGenerator.fillBusinessObject(bo, name, packageName, new BigInteger(""+parseId), qName, javaName, javaTag, null, null, null, null); } //we create and add the new XML node FieldBusinessObject f = null; f = DataLibGenerator.createFieldBusinessObject(modelFactory, name, null, "", "", qName, javaName, javaTag, new BigInteger(""+parseId), null, parent, null, bo, null); //if we are on the first level after the ResponseBusinessObject // if(fieldXML == null){ // ((ResponseBusinessObject)parent).getXmlContentFields().add(f); // f.setXmlParent(parent.getRelatedField()); // } else { f.setXmlParent(fieldXML); fieldXML.getXmlContentFields().add(f); // } bo.setRelatedField(f); fieldXML = f; parseId++; //we increment the parseId counter //we manage the attributes linking processBOAttributes(attributes, bo, f); //we add the BusinessObject to the parent parent.getChilds().add(bo); //we set the parent of the new node and set the current parent as the new node bo.setParent(parent); parent = bo; prefixList.clear(); prefixName = name; // we declare the prefix name } else { //we are in a node that has to be include inside the parent's content fields //if the previous content field is just a container (that means that it does not contain data, just nodes) if(isFillingField){ bo.getContentFields().remove(field); //we remove it from the current business object field.getRelatedField().setRelatedField(null); } else isFillingField = true; String javaName = getJavaName(name); ParameterType type = getParameterType(attributes.getValue(DataLibLabels.XML_TYPE)); String defaultValue = attributes.getValue(DataLibLabels.XML_DEFAULT); //we create the current field field = DataLibGenerator.createField(modelFactory, name, type, "", defaultValue, qName, javaName, javaTag, new BigInteger(""+parseId), null, bo, null); //we create and add the new XML node Field f = null; f = DataLibGenerator.createField(modelFactory, name, type, "", defaultValue, qName, javaName, javaTag, new BigInteger(""+parseId), null, bo, null); f.setXmlParent(fieldXML); f.setRelatedField(field); fieldXML.getXmlContentFields().add(f); fieldXML = f; field.setRelatedField(f); parseId++; //we increment the parseId counter //we update the prefix name prefixList.add(name); prefixName = prefixName + name; //we manage the attributes linking processFieldAttributes(attributes, f); bo.getContentFields().add(field); } } contentLevel++; } break; case CONFIG: if (qName.equals(DataLibLabels.XML_HTTP_METHOD)) { mState = HTTP_METHOD; } else if (qName.equals(DataLibLabels.XML_PARSE_TYPE)) { mState = PARSE_TYPE; } else if (qName.equals(DataLibLabels.XML_OPTIONS)) { mState = OPTIONS; } else if (qName.equals(DataLibLabels.XML_PARAMETERS)) { mState = PARAMETERS; } break; case OPTIONS: mState = OPTIONS_OPTION; if (qName.equals(DataLibLabels.XML_OPTION_CONSERVE_COOKIE)) { webservice.getOptions().add(DataLibOption.CONSERVE_COOKIE); } else if (qName.equals(DataLibLabels.XML_OPTION_DATABASE_CACHE_DISABLED)) { webservice.getOptions().add(DataLibOption.DATA_BASE_CACHE_DISABLED); webservice.setCached(false); //we update the webservice cached value cached = false; } else if (qName.equals(DataLibLabels.XML_OPTION_HELPER_CACHE_DISABLED)) { webservice.getOptions().add(DataLibOption.HELPER_CACHE_DISABLED); } else if (qName.equals(DataLibLabels.XML_OPTION_HOST_VERIFIER_DISABLED)) { webservice.getOptions().add(DataLibOption.HOST_VERIFIER_DISABLED); } else if (qName.equals(DataLibLabels.XML_OPTION_SEND_WITH_PARCELABLE)) { webservice.getOptions().add(DataLibOption.SEND_WITH_PARCELABLE); } break; case PARAMETERS: //description String description = attributes.getValue(DataLibLabels.XML_DESCRIPTION); //type ParameterType type = getParameterType(attributes.getValue(DataLibLabels.XML_TYPE)); //fingerprintKey boolean isKey = true; String fingerprintKey = attributes.getValue(DataLibLabels.XML_FINGERPRINT_KEY); if(fingerprintKey != null){ //we parse the attribute following the Boolean's parse method isKey = Boolean.parseBoolean(fingerprintKey); } //we eventually add the url parameter int urlIndex = -1; String urlParam = attributes.getValue(DataLibLabels.XML_URL_PARAMETERS); if(urlParam != null){ urlIndex = Integer.parseInt(urlParam); EList<Parameter> urlParamsList = webservice.getUrlParameters(); //we scope the urlIndex and set it as the maximum acceptable value for the actual array int index = (urlIndex+1 > urlParamsList.size()) ? urlParamsList.size() : urlIndex; webservice.getUrlParameters().add(index, DataLibGenerator.createParameter(modelFactory, qName, type, description, urlIndex, isKey)); } webservice.getParameters().add(DataLibGenerator.createParameter(modelFactory, qName, type, description, urlIndex, isKey)); default: // do nothing break; } } @Override public void characters(final char[] ch, final int start, final int length) throws SAXException { mBuilder.append(ch, start, length); } @Override public void endElement(final String uri, final String localName, final String qName) throws SAXException { switch (mState) { case PROJECT: if (qName.equals(DataLibLabels.XML_PROJECT)) { mState = UNKNOWN; } break; case WEBSERVICE: if (qName.equals(DataLibLabels.XML_WEBSERVICE)) { mState = PROJECT; } break; case CONFIG: if (qName.equals(DataLibLabels.XML_CONFIG)) { mState = WEBSERVICE; //we check the URL format EList<Parameter> params = webservice.getUrlParameters(); if(params.size() > 0){ Parameter lastParams = params.get(params.size()-1); String[] array = new String[lastParams.getUrlParameter()+1]; try{ for (Parameter parameter : params) { array[parameter.getUrlParameter()] = parameter.getName(); } } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException("The URL parameters are not well numbered. Check that is correct and add the corresponding parameters into the <"+DataLibLabels.XML_PARAMETERS+"> content's. Use "+DataLibLabels.XML_URL_PARAMETERS+" attribute to define the parameter as a URL parameter specifying its ID"); } String test = MessageFormat.format(webservice.getUrl(), (Object[])array); System.out.println(test); } else { System.out.println(webservice.getUrl()); } } break; case HTTP_METHOD: if (qName.equals(DataLibLabels.XML_HTTP_METHOD)) { mState = CONFIG; webservice.setMethod(getHttpMethod(mBuilder.toString())); } break; case PARSE_TYPE: if (qName.equals(DataLibLabels.XML_PARSE_TYPE)) { mState = CONFIG; webservice.setParseType(getParseType(mBuilder.toString())); } break; case OPTIONS: if (qName.equals(DataLibLabels.XML_OPTIONS)) { mState = CONFIG; } break; case OPTIONS_OPTION: mState = OPTIONS; break; case PARAMETERS: if (qName.equals(DataLibLabels.XML_PARAMETERS)) { mState = CONFIG; } break; case CONTENT: //if we finish to read the content if (qName.equals(responseTagName)) { mState = WEBSERVICE; contentLevel--; String content = mBuilder.toString(); content = content.replaceAll("\\s+", ""); if(isResponseField && !content.equals("")){ //we get the name String name = mCurrentAttributes.getValue(DataLibLabels.XML_NAME); if(name == null) name = qName; String javaTag = getJavaTag(qName); String javaName = getJavaName(name); ParameterType type = getParameterType(mBuilder.toString()); String defaultValue = mCurrentAttributes.getValue(DataLibLabels.XML_DEFAULT); //we create the current field field = DataLibGenerator.createField(modelFactory, name, type, "", defaultValue, qName, javaName, javaTag, new BigInteger(""+parseId), null, bo, null); // //we update the prefix name // prefixList.add(name); // prefixName = prefixName + name; // //we manage the attributes linking // processFieldAttributes(mCurrentAttributes, f); bo.getContentFields().add(field); tempField.setRelatedField(field); } //if we are reading a field } else if(isFillingField) { ParameterType type = getParameterType(mBuilder.toString()); field.setType(type); fieldXML.setType(type); field = null; isFillingField = false; fieldXML = fieldXML.getXmlParent(); contentLevel--; //we pop the last name prefixList.remove(prefixList.size()-1); //if we are reading a business object } else { contentLevel--; bo = bo.getParent(); parent = parent.getParent(); fieldXML = fieldXML.getXmlParent(); } javaTagStack.pop(); break; default: // do nothing break; } mBuilder.setLength(0); } private HttpMethod getHttpMethod(String value) { if(value == null) return DataLibConfig.DEFAUT_WEBSERVICE_HTTP_METHOD; if(value.equalsIgnoreCase(HttpMethod.GET.getName())) return HttpMethod.GET; if(value.equalsIgnoreCase(HttpMethod.DELETE.getName())) return HttpMethod.DELETE; if(value.equalsIgnoreCase(HttpMethod.HEAD.getName())) return HttpMethod.HEAD; if(value.equalsIgnoreCase(HttpMethod.POST.getName())) return HttpMethod.POST; if(value.equalsIgnoreCase(HttpMethod.PUT.getName())) return HttpMethod.PUT; if(value.equalsIgnoreCase(HttpMethod.SOAP.getName())) return HttpMethod.SOAP; return DataLibConfig.DEFAUT_WEBSERVICE_HTTP_METHOD; } private ParseType getParseType(String value) { if(value == null) return DataLibConfig.DEFAUT_WEBSERVICE_PARSE_TYPE; if(value.equalsIgnoreCase(ParseType.SAX.getName())) return ParseType.SAX; if(value.equalsIgnoreCase(ParseType.JSON.getName())) return ParseType.JSON; if(value.equalsIgnoreCase(ParseType.IMAGE.getName())) return ParseType.IMAGE; if(value.equalsIgnoreCase(ParseType.CUSTOM.getName())) return ParseType.CUSTOM; return DataLibConfig.DEFAUT_WEBSERVICE_PARSE_TYPE; } private ParameterType getParameterType(String value) { if(value == null) return DataLibConfig.DEFAUT_WEBSERVICE_PARAMETER_TYPE; if(value.equalsIgnoreCase(ParameterType.BOOLEAN.getName())) return ParameterType.BOOLEAN; if(value.equalsIgnoreCase(ParameterType.FLOAT.getName())) return ParameterType.FLOAT; if(value.equalsIgnoreCase(ParameterType.INT.getName()) || value.equalsIgnoreCase("integer")) return ParameterType.INT; if(value.equalsIgnoreCase(ParameterType.STRING.getName())) return ParameterType.STRING; return DataLibConfig.DEFAUT_WEBSERVICE_PARAMETER_TYPE; } private String getPrefixName(){ StringBuilder prefix = new StringBuilder(); for (int i = 0; i < prefixList.size(); i++) { String item = prefixList.get(i); if(item.length() > 0){ prefix.append(Character.toUpperCase(item.charAt(0))); prefix.append(item.substring(1)); } else prefix.append(item); } return prefix.toString(); } public DataLibProject getParseResult(){ return project; } private void processBOAttributes(final Attributes attributes, BusinessObject businessObject, Field field) { for (int i = 0; i < attributes.getLength(); i++) { if(!attributes.getQName(i).startsWith(DataLibLabels.XML_PREFIX)){ ParameterType typeP = getParameterType(attributes.getValue(i)); String xmlName = attributes.getQName(i); String upperName = Character.toUpperCase(xmlName.charAt(0))+xmlName.substring(1); String javaName = getPrefixName()+upperName; String javaTag = getJavaTag(xmlName); String name = getPrefixName()+upperName; businessObject.getAttributes().add(DataLibGenerator.createField(modelFactory, name, typeP, "", "", xmlName, javaName, javaTag, new BigInteger("-1"), null, bo, null)); if(field != null) field.getXmlAttributes().add(DataLibGenerator.createField(modelFactory, name, typeP, "", "", xmlName, javaName, javaTag, new BigInteger("-1"), null, bo, null)); else ((ResponseBusinessObject) businessObject).getXmlAttributes().add(DataLibGenerator.createField(modelFactory, name, typeP, "", "", xmlName, javaName, javaTag, new BigInteger("-1"), null, bo, null)); } } } private void processFieldAttributes(final Attributes attributes, Field f) { for (int i = 0; i < attributes.getLength(); i++) { if(!attributes.getQName(i).startsWith(DataLibLabels.XML_PREFIX)){ ParameterType typeP = getParameterType(attributes.getValue(i)); String xmlName = attributes.getQName(i); String upperName = Character.toUpperCase(xmlName.charAt(0))+xmlName.substring(1); String javaName = getPrefixName()+upperName; String javaTag = getJavaTag(xmlName); String name = getPrefixName()+upperName; bo.getAttributes().add(DataLibGenerator.createField(modelFactory, name, typeP, "", "", xmlName, javaName, javaTag, new BigInteger("-1"), null, bo, null)); field.getXmlAttributes().add(DataLibGenerator.createField(modelFactory, name, typeP, "", "", xmlName, javaName, javaTag, new BigInteger("-1"), null, bo, null)); f.getXmlAttributes().add(DataLibGenerator.createField(modelFactory, name, typeP, "", "", xmlName, javaName, javaTag, new BigInteger("-1"), null, bo, null)); } } } private String getJavaName(String name) { // javaName = null; // while(javaName == null){ // if(javaNameList.contains(name)); // } return name; } private String getJavaTag(String name) { StringBuilder b = new StringBuilder(); int size = javaTagStack.size(); for (int i = 0; i < size; i++) { b.append(javaTagStack.get(i).toUpperCase()); if(i<=size-2) b.append("_"); } return b.toString(); } }