http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp ---------------------------------------------------------------------- diff --git a/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp b/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp index db37577..0885ad0 100644 --- a/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp +++ b/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp @@ -1,332 +1,332 @@ -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. ---> -<%@page - import="org.apache.olingo.odata2.jpa.processor.ref.factory.JPAEntityManagerFactory"%> -<%@page import="java.util.List"%> -<%@page import="javax.persistence.EntityManager"%> -<%@page import="javax.persistence.EntityManagerFactory"%> -<%@page import="javax.persistence.Persistence"%> -<%@page import="javax.persistence.Query"%> -<%@page - import="org.apache.olingo.odata2.jpa.processor.ref.web.JPAReferenceServiceFactory"%> -<%@page - import="org.apache.olingo.odata2.jpa.processor.ref.util.DataGenerator"%> - -<%@ page language="java" contentType="text/html; charset=UTF-8" - pageEncoding="UTF-8"%> -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<title>Apache Olingo - OData2 JPA Processor Library</title> -<style type="text/css"> -body { - font-family: Arial, sans-serif; - font-size: 13px; - line-height: 18px; - color: blue; - background-color: #ffffff; -} - -a { - color: blue; - text-decoration: none; -} - -a:focus { - outline: thin dotted #4076cb; - outline-offset: -1px; -} - -a:hover,a:active { - outline: 0; -} - -a:hover { - color: #404a7e; - text-decoration: underline; -} - -h1,h2,h3,h4,h5,h6 { - margin: 9px 0; - font-family: inherit; - font-weight: bold; - line-height: 1; - color: blue; -} - -h1 { - font-size: 36px; - line-height: 40px; -} - -h2 { - font-size: 30px; - line-height: 40px; -} - -h3 { - font-size: 24px; - line-height: 40px; -} - -h4 { - font-size: 18px; - line-height: 20px; -} - -h5 { - font-size: 14px; - line-height: 20px; -} - -h6 { - font-size: 12px; - line-height: 20px; -} - -.logo { - float: right; -} - -ul { - padding: 0; - margin: 0 0 9px 25px; -} - -ul ul { - margin-bottom: 0; -} - -li { - line-height: 18px; -} - -hr { - margin: 18px 0; - border: 0; - border-top: 1px solid #cccccc; - border-bottom: 1px solid #ffffff; -} - -table { - border-collapse: collapse; - border-spacing: 10px; - border: 0px; -} - -th,td { - border: 0px solid; - padding: 20px; -} - -.code { - font-family: "Courier New", monospace; - font-size: 13px; - line-height: 18px; -} -</style> -</head> -<body> - <h1>Apache Olingo - OData2 JPA Processor Library</h1> - <hr /> - <table width=100% cellspacing="1" cellpadding="1"> - <tr> - <td width=50%><h2>Reference Scenario</h2></td> - <td width="50%"> - <table cellspacing="1" cellpadding="1"> - <tr align="center"> - <td align="right" width="80%"><font color="green"><small> - <% - EntityManagerFactory entityManagerFactory = - JPAEntityManagerFactory.getEntityManagerFactory("salesorderprocessing"); - EntityManager entityManager = entityManagerFactory - .createEntityManager(); - System.out.println("Data Gen " + entityManager.hashCode()); - DataGenerator dataGenerator = new DataGenerator(entityManager); - - Number result1 = null; - Number existingCount = null; - - String msg = null; - if (request.getParameter("button") != null) { - if (request.getParameter("button").equalsIgnoreCase("Generate")) { - Query q = entityManager - .createQuery("SELECT COUNT(x) FROM SalesOrderHeader x"); - existingCount = (Number) q.getSingleResult(); - if (existingCount.intValue() < 10) { // Generate only if no data! - dataGenerator.generate(); - result1 = (Number) q.getSingleResult(); - System.out - .println("Data not existing earlier.... Generated number of Items - " - + result1); - msg = result1 + " items generated. "; - - } else { - System.err - .println("Data already existing.... No Item generated by Data Generator !!"); - msg = "Data exists. No Item generated !!"; - } - } else { //Clean - - // Check if data already exists - Query q = entityManager - .createQuery("SELECT COUNT(x) FROM SalesOrderHeader x"); - Number result = (Number) q.getSingleResult(); - if (result.intValue() > 0) { // Generate only if no data! - dataGenerator.clean(); - msg = "Data Cleaned. " + result + " items cleaned."; - } else { - msg = " Nothing to clean!!"; - } - } - %> <%=(msg)%> - </small> </font></td> - <% - } - %> - <td width="10%"> - <form name="form1" method="get"> - <input type="hidden" name="button" value="Generate"> <input - type="submit" value="Generate Data" width="100%"> - </form> - </td> - <td width="10%"> - - <form name="form2" method="get"> - <input type="hidden" name="button" value="Clean"> <input - type="submit" value=" Clean Data " width="100%"> - </form> - </td> - </tr> - </table> - </td> - </tr> - </table> - <table width=100%> - <tr> - <td valign="top"> - <h3>Service Document and Metadata</h3> - <ul> - <li><a href="SalesOrderProcessing.svc?_wadl" target="_blank">wadl</a></li> - <li><a href="SalesOrderProcessing.svc/" target="_blank">service - document</a></li> - <li><a href="SalesOrderProcessing.svc/$metadata" - target="_blank">metadata</a></li> - </ul> - <h3>EntitySets</h3> - <ul> - <li><a href="SalesOrderProcessing.svc/SalesOrders" - target="_blank">SalesOrders</a></li> - <li><a href="SalesOrderProcessing.svc/SalesOrderLineItems" - target="_blank">SalesOrderLineItems</a></li> - <li><a href="SalesOrderProcessing.svc/Materials" - target="_blank">Materials</a></li> - <li><a href="SalesOrderProcessing.svc/Stores" target="_blank">Stores</a></li> - </ul> - <h3>Entities</h3> - <ul> - <li><a href="SalesOrderProcessing.svc/SalesOrders(2L)" - target="_blank">SalesOrders(2L)</a></li> - <li><a - href="SalesOrderProcessing.svc/SalesOrderLineItems(LiId=10L,SoId=2L)" - target="_blank">SalesOrderLineItems(LiId=10L,SoId=2L)</a></li> - <li><a href="SalesOrderProcessing.svc/Materials(111L)" - target="_blank">Materials(111L)</a></li> - <li><a href="SalesOrderProcessing.svc/Stores(131L)" - target="_blank">Stores(131L)</a></li> - - </ul> - <h3>Navigation</h3> - <ul> - <li><a - href="SalesOrderProcessing.svc/SalesOrders(2L)/SalesOrderLineItemDetails" - target="_blank">SalesOrders(2L)/SalesOrderLineItemDetails</a></li> - <li><a - href="SalesOrderProcessing.svc/SalesOrders(2L)/SalesOrderLineItemDetails" - target="_blank">SalesOrders(2L)/SalesOrderLineItemDetails</a></li> - <li><a - href="SalesOrderProcessing.svc/SalesOrderLineItems(LiId=10L,SoId=2L)/MaterialDetails" - target="_blank">SalesOrderLineItems(LiId=10L,SoId=2L)/MaterialDetails</a></li> - <li><a - href="SalesOrderProcessing.svc/Materials(112L)/StoreDetails" - target="_blank">Materials(112L)/StoreDetails</a></li> - - </ul> - <h3>$expand</h3> - <ul> - <li><a - href="SalesOrderProcessing.svc/SalesOrders?$expand=SalesOrderLineItemDetails" - target="_blank">SalesOrders?$expand=SalesOrderLineItemDetails</a></li> - <li><a - href="SalesOrderProcessing.svc/SalesOrders(2L)?$expand=SalesOrderLineItemDetails" - target="_blank">SalesOrders(2L)?$expand=SalesOrderLineItemDetails</a></li> - <li><a - href="SalesOrderProcessing.svc/SalesOrders?$expand=SalesOrderLineItemDetails/MaterialDetails,SalesOrderLineItemDetails/MaterialDetails/StoreDetails,NotesDetails" - target="_blank">SalesOrders?$expand=SalesOrderLineItemDetails/MaterialDetails,SalesOrderLineItemDetails/MaterialDetails/StoreDetails,NotesDetails</a></li> - <li><a - href="SalesOrderProcessing.svc/SalesOrders(2L)?$expand=SalesOrderLineItemDetails/MaterialDetails,SalesOrderLineItemDetails/MaterialDetails/StoreDetails,NotesDetails" - target="_blank">SalesOrders(2L)?$expand=SalesOrderLineItemDetails/MaterialDetails,SalesOrderLineItemDetails/MaterialDetails/StoreDetails,NotesDetails</a></li> - - </ul> - <h3>Function Imports</h3> - <ul> - <li><a - href="SalesOrderProcessing.svc/FindAllSalesOrders?DeliveryStatusCode='01'" - target="_blank">SalesOrderProcessing.svc/FindAllSalesOrders?DeliveryStatusCode='01'</a></li> - <li><a href="SalesOrderProcessing.svc/orderValue?SoId=2L" - target="_blank">SalesOrderProcessing.svc/orderValue?SoId=2L</a></li> - </ul> - <h3>Paging</h3> - <ul> - <li><a - href="SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages" - target="_blank">SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages"</a></li> - <li><a - href="SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages&$skiptoken=5" - target="_blank">SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages&$skiptoken=5</a></li> - <li><a - href="SalesOrderProcessing.svc/SalesOrders?$top=1&$skip=4&$inlinecount=allpages&$skiptoken=5" - target="_blank">SalesOrderProcessing.svc/SalesOrders?$top=1&$skip=4&$inlinecount=allpages&$skiptoken=5</a></li> - </ul> - </td> - <td valign="top"> </td> - <td valign="bottom"> - <div class="code"> - <% - String version = "gen/version.html"; - %> - <% - try { - %> - <jsp:include page='<%=version%>' /> - <% - } catch (Exception e) { - %> - <p>IDE Build</p> - <% - } - %> - </div> - </td> - </tr> - </table> -</body> -</html> - +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +--> +<%@page + import="org.apache.olingo.odata2.jpa.processor.ref.factory.JPAEntityManagerFactory"%> +<%@page import="java.util.List"%> +<%@page import="javax.persistence.EntityManager"%> +<%@page import="javax.persistence.EntityManagerFactory"%> +<%@page import="javax.persistence.Persistence"%> +<%@page import="javax.persistence.Query"%> +<%@page + import="org.apache.olingo.odata2.jpa.processor.ref.web.JPAReferenceServiceFactory"%> +<%@page + import="org.apache.olingo.odata2.jpa.processor.ref.util.DataGenerator"%> + +<%@ page language="java" contentType="text/html; charset=UTF-8" + pageEncoding="UTF-8"%> +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<title>Apache Olingo - OData2 JPA Processor Library</title> +<style type="text/css"> +body { + font-family: Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: blue; + background-color: #ffffff; +} + +a { + color: blue; + text-decoration: none; +} + +a:focus { + outline: thin dotted #4076cb; + outline-offset: -1px; +} + +a:hover,a:active { + outline: 0; +} + +a:hover { + color: #404a7e; + text-decoration: underline; +} + +h1,h2,h3,h4,h5,h6 { + margin: 9px 0; + font-family: inherit; + font-weight: bold; + line-height: 1; + color: blue; +} + +h1 { + font-size: 36px; + line-height: 40px; +} + +h2 { + font-size: 30px; + line-height: 40px; +} + +h3 { + font-size: 24px; + line-height: 40px; +} + +h4 { + font-size: 18px; + line-height: 20px; +} + +h5 { + font-size: 14px; + line-height: 20px; +} + +h6 { + font-size: 12px; + line-height: 20px; +} + +.logo { + float: right; +} + +ul { + padding: 0; + margin: 0 0 9px 25px; +} + +ul ul { + margin-bottom: 0; +} + +li { + line-height: 18px; +} + +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #cccccc; + border-bottom: 1px solid #ffffff; +} + +table { + border-collapse: collapse; + border-spacing: 10px; + border: 0px; +} + +th,td { + border: 0px solid; + padding: 20px; +} + +.code { + font-family: "Courier New", monospace; + font-size: 13px; + line-height: 18px; +} +</style> +</head> +<body> + <h1>Apache Olingo - OData2 JPA Processor Library</h1> + <hr /> + <table width=100% cellspacing="1" cellpadding="1"> + <tr> + <td width=50%><h2>Reference Scenario</h2></td> + <td width="50%"> + <table cellspacing="1" cellpadding="1"> + <tr align="center"> + <td align="right" width="80%"><font color="green"><small> + <% + EntityManagerFactory entityManagerFactory = + JPAEntityManagerFactory.getEntityManagerFactory("salesorderprocessing"); + EntityManager entityManager = entityManagerFactory + .createEntityManager(); + System.out.println("Data Gen " + entityManager.hashCode()); + DataGenerator dataGenerator = new DataGenerator(entityManager); + + Number result1 = null; + Number existingCount = null; + + String msg = null; + if (request.getParameter("button") != null) { + if (request.getParameter("button").equalsIgnoreCase("Generate")) { + Query q = entityManager + .createQuery("SELECT COUNT(x) FROM SalesOrderHeader x"); + existingCount = (Number) q.getSingleResult(); + if (existingCount.intValue() < 10) { // Generate only if no data! + dataGenerator.generate(); + result1 = (Number) q.getSingleResult(); + System.out + .println("Data not existing earlier.... Generated number of Items - " + + result1); + msg = result1 + " items generated. "; + + } else { + System.err + .println("Data already existing.... No Item generated by Data Generator !!"); + msg = "Data exists. No Item generated !!"; + } + } else { //Clean + + // Check if data already exists + Query q = entityManager + .createQuery("SELECT COUNT(x) FROM SalesOrderHeader x"); + Number result = (Number) q.getSingleResult(); + if (result.intValue() > 0) { // Generate only if no data! + dataGenerator.clean(); + msg = "Data Cleaned. " + result + " items cleaned."; + } else { + msg = " Nothing to clean!!"; + } + } + %> <%=(msg)%> + </small> </font></td> + <% + } + %> + <td width="10%"> + <form name="form1" method="get"> + <input type="hidden" name="button" value="Generate"> <input + type="submit" value="Generate Data" width="100%"> + </form> + </td> + <td width="10%"> + + <form name="form2" method="get"> + <input type="hidden" name="button" value="Clean"> <input + type="submit" value=" Clean Data " width="100%"> + </form> + </td> + </tr> + </table> + </td> + </tr> + </table> + <table width=100%> + <tr> + <td valign="top"> + <h3>Service Document and Metadata</h3> + <ul> + <li><a href="SalesOrderProcessing.svc?_wadl" target="_blank">wadl</a></li> + <li><a href="SalesOrderProcessing.svc/" target="_blank">service + document</a></li> + <li><a href="SalesOrderProcessing.svc/$metadata" + target="_blank">metadata</a></li> + </ul> + <h3>EntitySets</h3> + <ul> + <li><a href="SalesOrderProcessing.svc/SalesOrders" + target="_blank">SalesOrders</a></li> + <li><a href="SalesOrderProcessing.svc/SalesOrderLineItems" + target="_blank">SalesOrderLineItems</a></li> + <li><a href="SalesOrderProcessing.svc/Materials" + target="_blank">Materials</a></li> + <li><a href="SalesOrderProcessing.svc/Stores" target="_blank">Stores</a></li> + </ul> + <h3>Entities</h3> + <ul> + <li><a href="SalesOrderProcessing.svc/SalesOrders(2L)" + target="_blank">SalesOrders(2L)</a></li> + <li><a + href="SalesOrderProcessing.svc/SalesOrderLineItems(LiId=10L,SoId=2L)" + target="_blank">SalesOrderLineItems(LiId=10L,SoId=2L)</a></li> + <li><a href="SalesOrderProcessing.svc/Materials(111L)" + target="_blank">Materials(111L)</a></li> + <li><a href="SalesOrderProcessing.svc/Stores(131L)" + target="_blank">Stores(131L)</a></li> + + </ul> + <h3>Navigation</h3> + <ul> + <li><a + href="SalesOrderProcessing.svc/SalesOrders(2L)/SalesOrderLineItemDetails" + target="_blank">SalesOrders(2L)/SalesOrderLineItemDetails</a></li> + <li><a + href="SalesOrderProcessing.svc/SalesOrders(2L)/SalesOrderLineItemDetails" + target="_blank">SalesOrders(2L)/SalesOrderLineItemDetails</a></li> + <li><a + href="SalesOrderProcessing.svc/SalesOrderLineItems(LiId=10L,SoId=2L)/MaterialDetails" + target="_blank">SalesOrderLineItems(LiId=10L,SoId=2L)/MaterialDetails</a></li> + <li><a + href="SalesOrderProcessing.svc/Materials(112L)/StoreDetails" + target="_blank">Materials(112L)/StoreDetails</a></li> + + </ul> + <h3>$expand</h3> + <ul> + <li><a + href="SalesOrderProcessing.svc/SalesOrders?$expand=SalesOrderLineItemDetails" + target="_blank">SalesOrders?$expand=SalesOrderLineItemDetails</a></li> + <li><a + href="SalesOrderProcessing.svc/SalesOrders(2L)?$expand=SalesOrderLineItemDetails" + target="_blank">SalesOrders(2L)?$expand=SalesOrderLineItemDetails</a></li> + <li><a + href="SalesOrderProcessing.svc/SalesOrders?$expand=SalesOrderLineItemDetails/MaterialDetails,SalesOrderLineItemDetails/MaterialDetails/StoreDetails,NotesDetails" + target="_blank">SalesOrders?$expand=SalesOrderLineItemDetails/MaterialDetails,SalesOrderLineItemDetails/MaterialDetails/StoreDetails,NotesDetails</a></li> + <li><a + href="SalesOrderProcessing.svc/SalesOrders(2L)?$expand=SalesOrderLineItemDetails/MaterialDetails,SalesOrderLineItemDetails/MaterialDetails/StoreDetails,NotesDetails" + target="_blank">SalesOrders(2L)?$expand=SalesOrderLineItemDetails/MaterialDetails,SalesOrderLineItemDetails/MaterialDetails/StoreDetails,NotesDetails</a></li> + + </ul> + <h3>Function Imports</h3> + <ul> + <li><a + href="SalesOrderProcessing.svc/FindAllSalesOrders?DeliveryStatusCode='01'" + target="_blank">SalesOrderProcessing.svc/FindAllSalesOrders?DeliveryStatusCode='01'</a></li> + <li><a href="SalesOrderProcessing.svc/orderValue?SoId=2L" + target="_blank">SalesOrderProcessing.svc/orderValue?SoId=2L</a></li> + </ul> + <h3>Paging</h3> + <ul> + <li><a + href="SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages" + target="_blank">SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages"</a></li> + <li><a + href="SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages&$skiptoken=5" + target="_blank">SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages&$skiptoken=5</a></li> + <li><a + href="SalesOrderProcessing.svc/SalesOrders?$top=1&$skip=4&$inlinecount=allpages&$skiptoken=5" + target="_blank">SalesOrderProcessing.svc/SalesOrders?$top=1&$skip=4&$inlinecount=allpages&$skiptoken=5</a></li> + </ul> + </td> + <td valign="top"> </td> + <td valign="bottom"> + <div class="code"> + <% + String version = "gen/version.html"; + %> + <% + try { + %> + <jsp:include page='<%=version%>' /> + <% + } catch (Exception e) { + %> + <p>IDE Build</p> + <% + } + %> + </div> + </td> + </tr> + </table> +</body> +</html> +
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-annotation/.gitignore ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-annotation/.gitignore b/odata2-lib/odata-annotation/.gitignore index 8b3fd61..29be3de 100644 --- a/odata2-lib/odata-annotation/.gitignore +++ b/odata2-lib/odata-annotation/.gitignore @@ -1,8 +1,8 @@ -.project -.classpath -.settings -target -bin -*.bak -classes -.DS_Store +.project +.classpath +.settings +target +bin +*.bak +classes +.DS_Store http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-annotation/src/main/java/META-INF/MANIFEST.MF ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-annotation/src/main/java/META-INF/MANIFEST.MF b/odata2-lib/odata-annotation/src/main/java/META-INF/MANIFEST.MF index 5e94951..254272e 100644 --- a/odata2-lib/odata-annotation/src/main/java/META-INF/MANIFEST.MF +++ b/odata2-lib/odata-annotation/src/main/java/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ -Manifest-Version: 1.0 -Class-Path: - +Manifest-Version: 1.0 +Class-Path: + http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java index 647b071..96aa4dd 100644 --- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java +++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java @@ -43,7 +43,11 @@ public class BatchException extends ODataMessageException { /** MISSING_CLOSE_DELIMITER requires 1 content value ('line number') */ public static final MessageReference MISSING_CLOSE_DELIMITER = createMessageReference(BatchException.class, "MISSING_CLOSE_DELIMITER"); - + + /** MISSONG MANDATORY HEADER requires 1 content value ('header name') */ + public static final MessageReference MISSING_MANDATORY_HEADER = createMessageReference(BatchException.class, + "MISSING_MANDATORY_HEADER"); + /** INVALID_QUERY_OPERATION_METHOD requires 1 content value ('line number') */ public static final MessageReference INVALID_QUERY_OPERATION_METHOD = createMessageReference(BatchException.class, "INVALID_QUERY_OPERATION_METHOD"); @@ -90,7 +94,7 @@ public class BatchException extends ODataMessageException { public static final MessageReference INVALID_ACCEPT_LANGUAGE_HEADER = createMessageReference(BatchException.class, "INVALID_ACCEPT_LANGUAGE_HEADER"); - /** INVALID_CONTENT_TRANSFER_ENCODING requires no content value */ + /** INVALID_CONTENT_TRANSFER_ENCODING requires 1 content value */ public static final MessageReference INVALID_CONTENT_TRANSFER_ENCODING = createMessageReference(BatchException.class, "INVALID_CONTENT_TRANSFER_ENCODING"); http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchParserResult.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchParserResult.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchParserResult.java new file mode 100644 index 0000000..842933d --- /dev/null +++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchParserResult.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ******************************************************************************/ +package org.apache.olingo.odata2.api.batch; + +/** + * A BatchParserResult + * + * <p> BatchParserResult represents a BatchRequestPart or a BatchResponse part. + * + */ +public interface BatchParserResult { + +} http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchRequestPart.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchRequestPart.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchRequestPart.java index 5e3e2f2..5f76a36 100644 --- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchRequestPart.java +++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchRequestPart.java @@ -26,7 +26,7 @@ import org.apache.olingo.odata2.api.processor.ODataRequest; * A BatchPart * <p> BatchPart represents a distinct MIME part of a Batch Request body. It can be ChangeSet or Query Operation */ -public interface BatchRequestPart { +public interface BatchRequestPart extends BatchParserResult { /** * Get the info if a BatchPart is a ChangeSet http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchResponsePart.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchResponsePart.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchResponsePart.java index dfafbdb..6133104 100644 --- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchResponsePart.java +++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchResponsePart.java @@ -29,7 +29,7 @@ import org.apache.olingo.odata2.api.rt.RuntimeDelegate; * response to a retrieve request * */ -public abstract class BatchResponsePart { +public abstract class BatchResponsePart implements BatchParserResult { /** * Get responses. If a BatchResponsePart is a response to a retrieve request, the list consists of one response. http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchSingleResponse.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchSingleResponse.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchSingleResponse.java index dc8c9b7..ddb3c02 100644 --- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchSingleResponse.java +++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchSingleResponse.java @@ -21,12 +21,14 @@ package org.apache.olingo.odata2.api.client.batch; import java.util.Map; import java.util.Set; +import org.apache.olingo.odata2.api.batch.BatchParserResult; + /** * A BatchSingleResponse * <p> BatchSingleResponse represents a single response of a Batch Response body. It can be a response to a change * request of ChangeSet or a response to a retrieve request */ -public interface BatchSingleResponse { +public interface BatchSingleResponse extends BatchParserResult { /** * @return a result code of the attempt to understand and satisfy the request */ http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/exception/ODataInternalServerErrorException.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/exception/ODataInternalServerErrorException.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/exception/ODataInternalServerErrorException.java new file mode 100644 index 0000000..49620f8 --- /dev/null +++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/exception/ODataInternalServerErrorException.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ******************************************************************************/ +package org.apache.olingo.odata2.api.exception; + +import org.apache.olingo.odata2.api.commons.HttpStatusCodes; + +public class ODataInternalServerErrorException extends ODataHttpException { + private static final long serialVersionUID = 1L; + + public static final MessageReference NOSERVICE = createMessageReference(ODataInternalServerErrorException.class, + "NOSERVICE"); + + public ODataInternalServerErrorException(final MessageReference messageReference) { + super(messageReference, HttpStatusCodes.INTERNAL_SERVER_ERROR); + } + + public ODataInternalServerErrorException(final MessageReference messageReference, final String errorCode) { + super(messageReference, HttpStatusCodes.INTERNAL_SERVER_ERROR, errorCode); + } + + public ODataInternalServerErrorException(final MessageReference messageReference, final Throwable cause) { + super(messageReference, cause, HttpStatusCodes.INTERNAL_SERVER_ERROR); + } + + public ODataInternalServerErrorException(final MessageReference messageReference, final Throwable cause, + final String errorCode) { + super(messageReference, cause, HttpStatusCodes.INTERNAL_SERVER_ERROR, errorCode); + } + +} http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java index 946fccf..5c8811c 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java @@ -6,9 +6,9 @@ * to you 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 @@ -19,18 +19,16 @@ package org.apache.olingo.odata2.core.batch; import java.util.ArrayList; -import java.util.Comparator; -import java.util.LinkedList; import java.util.List; -import java.util.Scanner; import java.util.TreeSet; -import java.util.regex.MatchResult; +import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.olingo.odata2.api.batch.BatchException; +import org.apache.olingo.odata2.api.exception.MessageReference; /** - * + * */ public class AcceptParser { @@ -48,45 +46,64 @@ public class AcceptParser { private static final double QUALITY_PARAM_FACTOR = 0.001; - public static List<String> parseAcceptHeaders(final String headerValue) throws BatchException { - TreeSet<Accept> acceptTree = getAcceptTree(); - List<String> acceptHeaders = new ArrayList<String>(); - Scanner acceptHeaderScanner = new Scanner(headerValue); - acceptHeaderScanner.useDelimiter(",\\s?"); - while (acceptHeaderScanner.hasNext()) { - if (acceptHeaderScanner.hasNext(REG_EX_ACCEPT_WITH_Q_FACTOR)) { - acceptHeaderScanner.next(REG_EX_ACCEPT_WITH_Q_FACTOR); - MatchResult result = acceptHeaderScanner.match(); - if (result.groupCount() == 2) { - String acceptHeaderValue = result.group(1); - double qualityFactor = result.group(2) != null ? Double.parseDouble(result.group(2)) : 1d; - qualityFactor = getQualityFactor(acceptHeaderValue, qualityFactor); - Accept acceptHeader = new Accept().setQuality(qualityFactor).setValue(acceptHeaderValue); + private List<String> acceptHeaderValues = new ArrayList<String>(); + private List<String> acceptLanguageHeaderValues = new ArrayList<String>(); + + public List<String> parseAcceptHeaders() throws BatchException { + return parseQualifiedHeader(acceptHeaderValues, + REG_EX_ACCEPT_WITH_Q_FACTOR, + BatchException.INVALID_ACCEPT_HEADER); + } + + public List<String> parseAcceptableLanguages() throws BatchException { + return parseQualifiedHeader(acceptLanguageHeaderValues, + REG_EX_ACCEPT_LANGUAGES_WITH_Q_FACTOR, + BatchException.INVALID_ACCEPT_LANGUAGE_HEADER); + } + + private List<String> parseQualifiedHeader(List<String> headerValues, Pattern regEx, MessageReference exectionMessage) + throws BatchException { + final TreeSet<Accept> acceptTree = new TreeSet<AcceptParser.Accept>(); + final List<String> acceptHeaders = new ArrayList<String>(); + + for (final String headerValue : headerValues) { + final String[] acceptParts = headerValue.split(","); + + for (final String part : acceptParts) { + final Matcher matcher = regEx.matcher(part.trim()); + + if (matcher.matches() && matcher.groupCount() == 2) { + final Accept acceptHeader = getQualifiedHeader(matcher); acceptTree.add(acceptHeader); } else { - String header = acceptHeaderScanner.next(); - acceptHeaderScanner.close(); - throw new BatchException(BatchException.INVALID_ACCEPT_HEADER.addContent(header), BAD_REQUEST); + throw new BatchException(exectionMessage.addContent(part), BAD_REQUEST); } - } else { - String header = acceptHeaderScanner.next(); - acceptHeaderScanner.close(); - throw new BatchException(BatchException.INVALID_ACCEPT_HEADER.addContent(header), BAD_REQUEST); } } + for (Accept accept : acceptTree) { - acceptHeaders.add(accept.getValue()); + if (!acceptHeaders.contains(accept.getValue())) { + acceptHeaders.add(accept.getValue()); + } } - acceptHeaderScanner.close(); return acceptHeaders; } - private static double getQualityFactor(final String acceptHeaderValue, double qualityFactor) { + private Accept getQualifiedHeader(final Matcher matcher) { + final String acceptHeaderValue = matcher.group(1); + double qualityFactor = matcher.group(2) != null ? Double.parseDouble(matcher.group(2)) : 1d; + qualityFactor = getQualityFactor(acceptHeaderValue, qualityFactor); + + return new Accept().setQuality(qualityFactor).setValue(acceptHeaderValue); + } + + private double getQualityFactor(final String acceptHeaderValue, double qualityFactor) { int paramNumber = 0; double typeFactor = 0.0; double subtypeFactor = 0.0; String[] mediaRange = acceptHeaderValue.split("(?=[^;]+);"); String[] mediaTypes = mediaRange[0].split("/"); + if (mediaTypes.length == 2) { String type = mediaTypes[0]; String subtype = mediaTypes[1]; @@ -101,58 +118,20 @@ public class AcceptParser { String[] parameters = mediaRange[1].split(";\\s?"); paramNumber = parameters.length; } + qualityFactor = qualityFactor + paramNumber * QUALITY_PARAM_FACTOR + typeFactor + subtypeFactor; return qualityFactor; } - - public static List<String> parseAcceptableLanguages(final String headerValue) throws BatchException { - List<String> acceptLanguages = new LinkedList<String>(); - TreeSet<Accept> acceptTree = getAcceptTree(); - Scanner acceptLanguageScanner = new Scanner(headerValue); - acceptLanguageScanner.useDelimiter(",\\s?"); - - while (acceptLanguageScanner.hasNext()) { - if (acceptLanguageScanner.hasNext(REG_EX_ACCEPT_LANGUAGES_WITH_Q_FACTOR)) { - acceptLanguageScanner.next(REG_EX_ACCEPT_LANGUAGES_WITH_Q_FACTOR); - MatchResult result = acceptLanguageScanner.match(); - if (result.groupCount() == 2) { - String languagerange = result.group(1); - double qualityFactor = result.group(2) != null ? Double.parseDouble(result.group(2)) : 1d; - acceptTree.add(new Accept().setQuality(qualityFactor).setValue(languagerange)); - } else { - String acceptLanguage = acceptLanguageScanner.next(); - acceptLanguageScanner.close(); - throw new BatchException(BatchException.INVALID_ACCEPT_LANGUAGE_HEADER.addContent(acceptLanguage), - BAD_REQUEST); - } - } else { - String acceptLanguage = acceptLanguageScanner.next(); - acceptLanguageScanner.close(); - throw new BatchException(BatchException.INVALID_ACCEPT_LANGUAGE_HEADER.addContent(acceptLanguage), BAD_REQUEST); - } - } - for (Accept accept : acceptTree) { - acceptLanguages.add(accept.getValue()); - } - acceptLanguageScanner.close(); - return acceptLanguages; + + public void addAcceptHeaderValue(final String headerValue) { + acceptHeaderValues.add(headerValue); } - private static TreeSet<Accept> getAcceptTree() { - TreeSet<Accept> treeSet = new TreeSet<Accept>(new Comparator<Accept>() { - @Override - public int compare(final Accept o1, final Accept o2) { - if (o1.getQuality() <= o2.getQuality()) { - return 1; - } else { - return -1; - } - } - }); - return treeSet; + public void addAcceptLanguageHeaderValue(final String headerValue) { + acceptLanguageHeaderValues.add(headerValue); } - private static class Accept { + private static class Accept implements Comparable<Accept> { private double quality; private String value; @@ -165,14 +144,18 @@ public class AcceptParser { return this; } - public double getQuality() { - return quality; - } - public Accept setQuality(final double quality) { this.quality = quality; return this; } + @Override + public int compareTo(Accept o) { + if (quality <= o.quality) { + return 1; + } else { + return -1; + } + } } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestParser.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestParser.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestParser.java deleted file mode 100644 index 6ac1445..0000000 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestParser.java +++ /dev/null @@ -1,614 +0,0 @@ -/******************************************************************************* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - ******************************************************************************/ -package org.apache.olingo.odata2.core.batch; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Scanner; -import java.util.Set; -import java.util.regex.MatchResult; -import java.util.regex.Pattern; - -import org.apache.olingo.odata2.api.batch.BatchException; -import org.apache.olingo.odata2.api.batch.BatchRequestPart; -import org.apache.olingo.odata2.api.commons.HttpContentType; -import org.apache.olingo.odata2.api.commons.HttpHeaders; -import org.apache.olingo.odata2.api.commons.ODataHttpMethod; -import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties; -import org.apache.olingo.odata2.api.processor.ODataRequest; -import org.apache.olingo.odata2.api.processor.ODataRequest.ODataRequestBuilder; -import org.apache.olingo.odata2.api.uri.PathInfo; -import org.apache.olingo.odata2.api.uri.PathSegment; -import org.apache.olingo.odata2.core.ODataPathSegmentImpl; -import org.apache.olingo.odata2.core.PathInfoImpl; -import org.apache.olingo.odata2.core.commons.Decoder; -import org.apache.olingo.odata2.core.exception.ODataRuntimeException; - -/** - * - */ -public class BatchRequestParser { - private static final String LF = "\n"; - private static final String REG_EX_OPTIONAL_WHITESPACE = "\\s?"; - private static final String REG_EX_ZERO_OR_MORE_WHITESPACES = "\\s*"; - private static final String ANY_CHARACTERS = ".*"; - - private static final Pattern REG_EX_BLANK_LINE = Pattern.compile("(|" + REG_EX_ZERO_OR_MORE_WHITESPACES + ")"); - private static final Pattern REG_EX_HEADER = Pattern.compile("([a-zA-Z\\-]+):" + REG_EX_OPTIONAL_WHITESPACE + "(.*)" - + REG_EX_ZERO_OR_MORE_WHITESPACES); - private static final Pattern REG_EX_VERSION = Pattern.compile("(?:HTTP/[0-9]\\.[0-9])"); - private static final Pattern REG_EX_ANY_BOUNDARY_STRING = Pattern.compile("--" + ANY_CHARACTERS - + REG_EX_ZERO_OR_MORE_WHITESPACES); - private static final Pattern REG_EX_REQUEST_LINE = Pattern.compile("(GET|POST|PUT|DELETE|MERGE|PATCH)\\s(.*)\\s?" - + REG_EX_VERSION + REG_EX_ZERO_OR_MORE_WHITESPACES); - private static final Pattern REG_EX_BOUNDARY_PARAMETER = Pattern.compile(REG_EX_OPTIONAL_WHITESPACE - + "boundary=(\".*\"|.*)" + REG_EX_ZERO_OR_MORE_WHITESPACES); - private static final Pattern REG_EX_CONTENT_TYPE = Pattern.compile(REG_EX_OPTIONAL_WHITESPACE - + HttpContentType.MULTIPART_MIXED); - private static final Pattern REG_EX_QUERY_PARAMETER = Pattern.compile("((?:\\$|)[^=]+)=([^=]+)"); - - private static final String REG_EX_BOUNDARY = - "([a-zA-Z0-9_\\-\\.'\\+]{1,70})|\"([a-zA-Z0-9_\\-\\.'\\+\\s\\" + - "(\\),/:=\\?]{1,69}[a-zA-Z0-9_\\-\\.'\\+\\(\\),/:=\\?])\""; // See RFC 2046 - - private String baseUri; - private PathInfo batchRequestPathInfo; - private String contentTypeMime; - private String boundary; - private String currentMimeHeaderContentId; - private int currentLineNumber = 0; - private final static Set<String> HTTP_CHANGESET_METHODS; - private final static Set<String> HTTP_BATCH_METHODS; - - static { - HashSet<String> httpChangesetMethods = new HashSet<String>(); - httpChangesetMethods.add("POST"); - httpChangesetMethods.add("PUT"); - httpChangesetMethods.add("DELETE"); - httpChangesetMethods.add("MERGE"); - httpChangesetMethods.add("PATCH"); - HTTP_CHANGESET_METHODS = Collections.unmodifiableSet(httpChangesetMethods); - - HashSet<String> httpBatchMethods = new HashSet<String>(); - httpBatchMethods.add("GET"); - HTTP_BATCH_METHODS = Collections.unmodifiableSet(httpBatchMethods); - } - - public BatchRequestParser(final String contentType, final EntityProviderBatchProperties properties) { - contentTypeMime = contentType; - batchRequestPathInfo = properties.getPathInfo(); - } - - public List<BatchRequestPart> parse(final InputStream in) throws BatchException { - Scanner scanner = new Scanner(in, BatchHelper.DEFAULT_ENCODING); - scanner.useDelimiter(LF); - baseUri = getBaseUri(); - List<BatchRequestPart> requestList; - try { - requestList = parseBatchRequest(scanner); - } finally {// NOPMD (suppress DoNotThrowExceptionInFinally) - scanner.close(); - try { - in.close(); - } catch (IOException e) { - throw new ODataRuntimeException(e); - } - } - return requestList; - } - - private List<BatchRequestPart> parseBatchRequest(final Scanner scanner) throws BatchException { - List<BatchRequestPart> requests = new LinkedList<BatchRequestPart>(); - if (contentTypeMime != null) { - boundary = getBoundary(contentTypeMime); - parsePreamble(scanner); - final String closeDelimiter = "--" + boundary + "--" + REG_EX_ZERO_OR_MORE_WHITESPACES; - while (scanner.hasNext() && !scanner.hasNext(closeDelimiter)) { - requests.add(parseMultipart(scanner, boundary, false)); - parseOptionalLine(scanner); - } - if (scanner.hasNext(closeDelimiter)) { - scanner.next(closeDelimiter); - currentLineNumber++; - } else { - throw new BatchException(BatchException.MISSING_CLOSE_DELIMITER.addContent(currentLineNumber)); - } - } else { - throw new BatchException(BatchException.MISSING_CONTENT_TYPE); - } - return requests; - } - - // The method parses additional information prior to the first boundary delimiter line - private void parsePreamble(final Scanner scanner) { - while (scanner.hasNext() && !scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) { - scanner.next(); - currentLineNumber++; - } - } - - private BatchRequestPart parseMultipart(final Scanner scanner, final String boundary, final boolean isChangeSet) - throws BatchException { - - if (scanner.hasNext("--" + boundary + REG_EX_ZERO_OR_MORE_WHITESPACES)) { - scanner.next(); - currentLineNumber++; - Map<String, String> mimeHeaders = parseHeaders(scanner); - currentMimeHeaderContentId = mimeHeaders.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH)); - - String contentType = mimeHeaders.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH)); - if (contentType == null) { - throw new BatchException(BatchException.MISSING_CONTENT_TYPE); - } - if (isChangeSet) { - return parseBatchRequestPartInChangeset(scanner, boundary, mimeHeaders, contentType); - } else { - return parseBatchRequestPart(scanner, boundary, mimeHeaders, contentType); - } - } else if (scanner.hasNext(boundary + REG_EX_ZERO_OR_MORE_WHITESPACES)) { - currentLineNumber++; - throw new BatchException(BatchException.INVALID_BOUNDARY_DELIMITER.addContent(currentLineNumber)); - } else if (scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) { - currentLineNumber++; - throw new BatchException(BatchException.NO_MATCH_WITH_BOUNDARY_STRING.addContent(boundary).addContent( - currentLineNumber)); - } else { - currentLineNumber++; - throw new BatchException(BatchException.MISSING_BOUNDARY_DELIMITER.addContent(currentLineNumber)); - } - } - - private BatchRequestPart parseBatchRequestPart(final Scanner scanner, final String boundary, - final Map<String, String> mimeHeaders, - final String contentType) throws BatchException { - if (HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType)) { - validateEncoding(mimeHeaders.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH))); - parseNewLine(scanner);// mandatory - List<ODataRequest> requests = new ArrayList<ODataRequest>(1); - requests.add(parseRequest(scanner, false, boundary)); - return new BatchRequestPartImpl(false, requests); - } else if (contentType.matches(REG_EX_OPTIONAL_WHITESPACE + HttpContentType.MULTIPART_MIXED + ANY_CHARACTERS)) { - String changeSetBoundary = getBoundary(contentType); - if (boundary.equals(changeSetBoundary)) { - throw new BatchException(BatchException.INVALID_CHANGESET_BOUNDARY.addContent(currentLineNumber)); - } - List<ODataRequest> changeSetRequests = new LinkedList<ODataRequest>(); - parseNewLine(scanner);// mandatory - Pattern changeSetCloseDelimiter = - Pattern.compile("--" + changeSetBoundary + "--" + REG_EX_ZERO_OR_MORE_WHITESPACES); - while (!scanner.hasNext(changeSetCloseDelimiter)) { - BatchRequestPart part = parseMultipart(scanner, changeSetBoundary, true); - changeSetRequests.addAll(part.getRequests()); - } - scanner.next(changeSetCloseDelimiter); - currentLineNumber++; - return new BatchRequestPartImpl(true, changeSetRequests); - } else { - throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED - + " or " + HttpContentType.APPLICATION_HTTP)); - } - } - - private BatchRequestPart parseBatchRequestPartInChangeset(final Scanner scanner, final String boundary, - final Map<String, String> mimeHeaders, - final String contentType) throws BatchException { - if (HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType)) { - validateEncoding(mimeHeaders.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH))); - parseNewLine(scanner);// mandatory - List<ODataRequest> requests = new ArrayList<ODataRequest>(1); - requests.add(parseRequest(scanner, true, boundary)); - return new BatchRequestPartImpl(false, requests); - } else { - throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.APPLICATION_HTTP)); - } - } - - private ODataRequest parseRequest(final Scanner scanner, final boolean isChangeSet, final String boundary) - throws BatchException { - if (scanner.hasNext(REG_EX_REQUEST_LINE)) { - scanner.next(REG_EX_REQUEST_LINE); - currentLineNumber++; - final String method; - final String uri; - MatchResult result = scanner.match(); - if (result.groupCount() == 2) { - method = result.group(1); - uri = result.group(2).trim(); - } else { - currentLineNumber++; - throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(scanner.next()).addContent( - currentLineNumber)); - } - PathInfo pathInfo = parseRequestUri(uri); - Map<String, String> queryParameters = parseQueryParameters(uri); - if (isChangeSet) { - if (!HTTP_CHANGESET_METHODS.contains(method)) { - throw new BatchException(BatchException.INVALID_CHANGESET_METHOD.addContent(currentLineNumber)); - } - } else if (!HTTP_BATCH_METHODS.contains(method)) { - throw new BatchException(BatchException.INVALID_QUERY_OPERATION_METHOD.addContent(currentLineNumber)); - } - ODataHttpMethod httpMethod = ODataHttpMethod.valueOf(method); - Map<String, List<String>> headers = parseRequestHeaders(scanner, boundary); - if (currentMimeHeaderContentId != null) { - List<String> headerList = new ArrayList<String>(); - headerList.add(currentMimeHeaderContentId); - headers.put(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), headerList); - } - - String contentType = getContentTypeHeader(headers); - List<String> acceptHeaders = getAcceptHeader(headers); - List<Locale> acceptLanguages = getAcceptLanguageHeader(headers); - InputStream body = new ByteArrayInputStream(new byte[0]); - if (isChangeSet) { - body = parseBody(scanner); - } - - ODataRequestBuilder requestBuilder = ODataRequest.method(httpMethod) - .queryParameters(queryParameters) - .requestHeaders(headers) - .pathInfo(pathInfo) - .acceptableLanguages(acceptLanguages) - .body(body) - .acceptHeaders(acceptHeaders); - - if (contentType != null) { - requestBuilder = requestBuilder.contentType(contentType); - } - return requestBuilder.build(); - } else { - currentLineNumber++; - throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(scanner.next()).addContent( - currentLineNumber)); - } - - } - - private Map<String, List<String>> parseRequestHeaders(final Scanner scanner, final String boundary) - throws BatchException { - Map<String, List<String>> headers = new HashMap<String, List<String>>(); - while (scanner.hasNext() - && !scanner.hasNext(REG_EX_BLANK_LINE) - && !scanner.hasNext("--" + boundary + REG_EX_ZERO_OR_MORE_WHITESPACES)) { - if (scanner.hasNext(REG_EX_HEADER)) { - scanner.next(REG_EX_HEADER); - currentLineNumber++; - MatchResult result = scanner.match(); - if (result.groupCount() == 2) { - String headerName = result.group(1).trim().toLowerCase(Locale.ENGLISH); - String headerValue = result.group(2).trim(); - if (HttpHeaders.ACCEPT.equalsIgnoreCase(headerName)) { - List<String> acceptHeaders = parseAcceptHeaders(headerValue); - headers.put(headerName, acceptHeaders); - } else if (HttpHeaders.ACCEPT_LANGUAGE.equalsIgnoreCase(headerName)) { - List<String> acceptLanguageHeaders = parseAcceptableLanguages(headerValue); - headers.put(headerName, acceptLanguageHeaders); - } else if (!BatchHelper.HTTP_CONTENT_ID.equalsIgnoreCase(headerName)) { - if (headers.containsKey(headerName)) { - headers.get(headerName).add(headerValue); - } else { - List<String> headerList = new ArrayList<String>(); - headerList.add(headerValue); - headers.put(headerName, headerList); - } - } else { - List<String> headerList = new ArrayList<String>(); - headerList.add(headerValue); - headers.put(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), headerList); - } - } - } else { - currentLineNumber++; - throw new BatchException(BatchException.INVALID_HEADER.addContent(scanner.next()) - .addContent(currentLineNumber)); - } - } - return headers; - } - - private PathInfo parseRequestUri(final String uri) throws BatchException { - PathInfoImpl pathInfo = new PathInfoImpl(); - pathInfo.setServiceRoot(batchRequestPathInfo.getServiceRoot()); - pathInfo.setPrecedingPathSegment(batchRequestPathInfo.getPrecedingSegments()); - final String odataPathSegmentsAsString; - final String queryParametersAsString; - try { - Scanner uriScanner = new Scanner(uri); - uriScanner.useDelimiter(LF); - URI uriObject = new URI(uri); - if (uriObject.isAbsolute()) { - Pattern regexRequestUri = Pattern.compile(baseUri + "/([^/][^?]*)(\\?.*)?"); - if (uriScanner.hasNext(regexRequestUri)) { - uriScanner.next(regexRequestUri); - MatchResult result = uriScanner.match(); - if (result.groupCount() == 2) { - odataPathSegmentsAsString = result.group(1); - queryParametersAsString = result.group(2) != null ? result.group(2) : ""; - } else { - uriScanner.close(); - throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber)); - } - } else { - uriScanner.close(); - throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber)); - } - } else { - Pattern regexRequestUri = Pattern.compile("([^/][^?]*)(\\?.*)?"); - if (uriScanner.hasNext(regexRequestUri)) { - uriScanner.next(regexRequestUri); - MatchResult result = uriScanner.match(); - if (result.groupCount() == 2) { - odataPathSegmentsAsString = result.group(1); - queryParametersAsString = result.group(2) != null ? result.group(2) : ""; - } else { - uriScanner.close(); - throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber)); - } - } else if (uriScanner.hasNext("/(.*)")) { - uriScanner.close(); - throw new BatchException(BatchException.UNSUPPORTED_ABSOLUTE_PATH.addContent(currentLineNumber)); - } else { - uriScanner.close(); - throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber)); - } - - } - uriScanner.close(); - pathInfo.setODataPathSegment(parseODataPathSegments(odataPathSegmentsAsString)); - if (!odataPathSegmentsAsString.startsWith("$")) { - String requestUri = baseUri + "/" + odataPathSegmentsAsString + queryParametersAsString; - pathInfo.setRequestUri(new URI(requestUri)); - } - return pathInfo; - } catch (URISyntaxException e) { - throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber), e); - } - - } - - private Map<String, String> parseQueryParameters(final String uri) throws BatchException { - Scanner uriScanner = new Scanner(uri); - uriScanner.useDelimiter("\n"); - Map<String, String> queryParametersMap = new HashMap<String, String>(); - Pattern regex = Pattern.compile("(?:" + baseUri + "/)?" + "[^?]+" + "\\?(.*)"); - if (uriScanner.hasNext(regex)) { - uriScanner.next(regex); - MatchResult uriResult = uriScanner.match(); - if (uriResult.groupCount() == 1) { - String queryParams = uriResult.group(1); - Scanner queryParamsScanner = new Scanner(queryParams); - queryParamsScanner.useDelimiter("&"); - while (queryParamsScanner.hasNext(REG_EX_QUERY_PARAMETER)) { - queryParamsScanner.next(REG_EX_QUERY_PARAMETER); - MatchResult result = queryParamsScanner.match(); - if (result.groupCount() == 2) { - String systemQueryOption = result.group(1); - String value = result.group(2); - queryParametersMap.put(systemQueryOption, Decoder.decode(value)); - } else { - queryParamsScanner.close(); - throw new BatchException(BatchException.INVALID_QUERY_PARAMETER); - } - } - queryParamsScanner.close(); - - } else { - uriScanner.close(); - throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber)); - } - } - uriScanner.close(); - return queryParametersMap; - } - - private List<PathSegment> parseODataPathSegments(final String odataPathSegmentsAsString) { - Scanner pathSegmentScanner = new Scanner(odataPathSegmentsAsString); - pathSegmentScanner.useDelimiter("/"); - List<PathSegment> odataPathSegments = new ArrayList<PathSegment>(); - while (pathSegmentScanner.hasNext()) { - odataPathSegments.add(new ODataPathSegmentImpl(pathSegmentScanner.next(), null)); - } - pathSegmentScanner.close(); - return odataPathSegments; - } - - private List<String> parseAcceptHeaders(final String headerValue) throws BatchException { - return AcceptParser.parseAcceptHeaders(headerValue); - } - - private List<String> parseAcceptableLanguages(final String headerValue) throws BatchException { - return AcceptParser.parseAcceptableLanguages(headerValue); - } - - private InputStream parseBody(final Scanner scanner) { - StringBuilder body = null; - final InputStream requestBody; - - while (scanner.hasNext() && !scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) { - if (!scanner.hasNext(REG_EX_ZERO_OR_MORE_WHITESPACES)) { - if (body == null) { - body = new StringBuilder(scanner.next()); - } else { - body.append(LF).append(scanner.next()); - } - } else { - scanner.next(); - } - currentLineNumber++; - } - - if (body != null) { - requestBody = new ByteArrayInputStream(BatchHelper.getBytes(body.toString())); - } else { - requestBody = new ByteArrayInputStream(new byte[0]); - } - return requestBody; - } - - private String getBoundary(final String contentType) throws BatchException { - Scanner contentTypeScanner = new Scanner(contentType); - contentTypeScanner.useDelimiter(";\\s?"); - if (contentTypeScanner.hasNext(REG_EX_CONTENT_TYPE)) { - contentTypeScanner.next(REG_EX_CONTENT_TYPE); - } else { - contentTypeScanner.close(); - throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED)); - } - if (contentTypeScanner.hasNext(REG_EX_BOUNDARY_PARAMETER)) { - contentTypeScanner.next(REG_EX_BOUNDARY_PARAMETER); - MatchResult result = contentTypeScanner.match(); - contentTypeScanner.close(); - if (result.groupCount() == 1 && result.group(1).trim().matches(REG_EX_BOUNDARY)) { - return trimQuota(result.group(1).trim()); - } else { - throw new BatchException(BatchException.INVALID_BOUNDARY); - } - } else { - contentTypeScanner.close(); - throw new BatchException(BatchException.MISSING_PARAMETER_IN_CONTENT_TYPE); - } - } - - private void validateEncoding(final String encoding) throws BatchException { - if (!BatchHelper.BINARY_ENCODING.equalsIgnoreCase(encoding)) { - throw new BatchException(BatchException.INVALID_CONTENT_TRANSFER_ENCODING); - } - } - - private Map<String, String> parseHeaders(final Scanner scanner) throws BatchException { - Map<String, String> headers = new HashMap<String, String>(); - while (scanner.hasNext() && !(scanner.hasNext(REG_EX_BLANK_LINE))) { - if (scanner.hasNext(REG_EX_HEADER)) { - scanner.next(REG_EX_HEADER); - currentLineNumber++; - MatchResult result = scanner.match(); - if (result.groupCount() == 2) { - String headerName = result.group(1).trim().toLowerCase(Locale.ENGLISH); - String headerValue = result.group(2).trim(); - headers.put(headerName, headerValue); - } - } else { - throw new BatchException(BatchException.INVALID_HEADER.addContent(scanner.next())); - } - } - return headers; - } - - private void parseNewLine(final Scanner scanner) throws BatchException { - if (scanner.hasNext() && scanner.hasNext(REG_EX_BLANK_LINE)) { - scanner.next(); - currentLineNumber++; - } else { - currentLineNumber++; - if (scanner.hasNext()) { - throw new BatchException(BatchException.MISSING_BLANK_LINE.addContent(scanner.next()).addContent( - currentLineNumber)); - } else { - throw new BatchException(BatchException.TRUNCATED_BODY.addContent(currentLineNumber)); - - } - } - } - - private void parseOptionalLine(final Scanner scanner) throws BatchException { - while (scanner.hasNext() && scanner.hasNext(REG_EX_BLANK_LINE)) { - scanner.next(); - currentLineNumber++; - } - } - - private String getBaseUri() throws BatchException { - if (batchRequestPathInfo != null) { - if (batchRequestPathInfo.getServiceRoot() != null) { - String baseUri = batchRequestPathInfo.getServiceRoot().toASCIIString(); - if (baseUri.lastIndexOf('/') == baseUri.length() - 1) { - baseUri = baseUri.substring(0, baseUri.length() - 1); - } - for (PathSegment precedingPS : batchRequestPathInfo.getPrecedingSegments()) { - baseUri = baseUri + "/" + precedingPS.getPath(); - } - return baseUri; - } - } else { - throw new BatchException(BatchException.INVALID_PATHINFO); - } - return null; - } - - private String trimQuota(String boundary) { - if (boundary.matches("\".*\"")) { - boundary = boundary.replace("\"", ""); - } - boundary = boundary.replaceAll("\\)", "\\\\)"); - boundary = boundary.replaceAll("\\(", "\\\\("); - boundary = boundary.replaceAll("\\?", "\\\\?"); - boundary = boundary.replaceAll("\\+", "\\\\+"); - return boundary; - } - - private List<String> getAcceptHeader(final Map<String, List<String>> headers) { - List<String> acceptHeaders = new ArrayList<String>(); - List<String> requestAcceptHeaderList = headers.get(HttpHeaders.ACCEPT.toLowerCase(Locale.ENGLISH)); - - if (requestAcceptHeaderList != null) { - acceptHeaders = requestAcceptHeaderList; - } - return acceptHeaders; - } - - private List<Locale> getAcceptLanguageHeader(final Map<String, List<String>> headers) { - List<String> requestAcceptLanguageList = headers.get(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase(Locale.ENGLISH)); - List<Locale> acceptLanguages = new ArrayList<Locale>(); - if (requestAcceptLanguageList != null) { - for (String acceptLanguage : requestAcceptLanguageList) { - String[] part = acceptLanguage.split("-"); - String language = part[0]; - String country = ""; - if (part.length == 2) { - country = part[part.length - 1]; - } - Locale locale = new Locale(language, country); - acceptLanguages.add(locale); - } - } - return acceptLanguages; - } - - private String getContentTypeHeader(final Map<String, List<String>> headers) { - List<String> requestContentTypeList = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH)); - String contentType = null; - if (requestContentTypeList != null) { - for (String requestContentType : requestContentTypeList) { - contentType = contentType != null ? contentType + "," + requestContentType : requestContentType; - } - } - return contentType; - } -} http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestWriter.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestWriter.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestWriter.java index a7ddfa1..9ec21cd 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestWriter.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestWriter.java @@ -37,7 +37,7 @@ public class BatchRequestWriter { private static final String COLON = ":"; private static final String SP = " "; - private static final String LF = "\r\n"; + private static final String CRLF = "\r\n"; public static final String BOUNDARY_PREAMBLE = "changeset"; public static final String HTTP_1_1 = "HTTP/1.1"; private String batchBoundary; @@ -50,7 +50,7 @@ public class BatchRequestWriter { throw new IllegalArgumentException(); } for (BatchPart batchPart : batchParts) { - writer.append("--").append(boundary).append(LF); + writer.append("--").append(boundary).append(CRLF); if (batchPart instanceof BatchChangeSet) { appendChangeSet((BatchChangeSet) batchPart); } else if (batchPart instanceof BatchQueryPart) { @@ -58,8 +58,10 @@ public class BatchRequestWriter { appendRequestBodyPart(request.getMethod(), request.getUri(), null, request.getHeaders(), request.getContentId()); } + + writer.append(CRLF); // CRLF belongs to the boundary delimiter or boundary closing delimiter } - writer.append(LF).append("--").append(boundary).append("--"); + writer.append("--").append(boundary).append("--"); InputStream batchRequestBody; batchRequestBody = new ByteArrayInputStream(BatchHelper.getBytes(writer.toString())); return batchRequestBody; @@ -71,41 +73,41 @@ public class BatchRequestWriter { boundary = BatchHelper.generateBoundary(BOUNDARY_PREAMBLE); } writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP).append( - HttpContentType.MULTIPART_MIXED + "; boundary=" + boundary).append(LF); + HttpContentType.MULTIPART_MIXED + "; boundary=" + boundary).append(CRLF); for (BatchChangeSetPart request : batchChangeSet.getChangeSetParts()) { - writer.append(LF).append("--").append(boundary).append(LF); + writer.append(CRLF).append("--").append(boundary).append(CRLF); appendRequestBodyPart(request.getMethod(), request.getUri(), request.getBody(), request.getHeaders(), request .getContentId()); } - writer.append(LF).append("--").append(boundary).append("--").append(LF); + writer.append(CRLF).append("--").append(boundary).append("--").append(CRLF); } private void appendRequestBodyPart(final String method, final String uri, final String body, final Map<String, String> headers, final String contentId) { boolean isContentLengthPresent = false; writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP).append(HttpContentType.APPLICATION_HTTP) - .append(LF); + .append(CRLF); writer.append(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING).append(COLON).append(SP) - .append(BatchHelper.BINARY_ENCODING).append(LF); + .append(BatchHelper.BINARY_ENCODING).append(CRLF); if (contentId != null) { - writer.append(BatchHelper.HTTP_CONTENT_ID).append(COLON).append(SP).append(contentId).append(LF); + writer.append(BatchHelper.HTTP_CONTENT_ID).append(COLON).append(SP).append(contentId).append(CRLF); } String contentLength = getHeaderValue(headers, HttpHeaders.CONTENT_LENGTH); if (contentLength != null && !contentLength.isEmpty()) { isContentLengthPresent = true; } - writer.append(LF); + writer.append(CRLF); writer.append(method).append(SP).append(uri).append(SP).append(HTTP_1_1); - writer.append(LF); + writer.append(CRLF); if (!isContentLengthPresent && body != null && !body.isEmpty()) { writer.append(HttpHeaders.CONTENT_LENGTH).append(COLON).append(SP).append(BatchHelper.getBytes(body).length) - .append(LF); + .append(CRLF); } appendHeader(headers); + writer.append(CRLF); if (body != null && !body.isEmpty()) { - writer.append(LF); writer.append(body); } } @@ -113,7 +115,7 @@ public class BatchRequestWriter { private void appendHeader(final Map<String, String> headers) { for (Map.Entry<String, String> headerMap : headers.entrySet()) { String name = headerMap.getKey(); - writer.append(name).append(COLON).append(SP).append(headerMap.getValue()).append(LF); + writer.append(name).append(COLON).append(SP).append(headerMap.getValue()).append(CRLF); } }
