diff --git a/build/tmpl/editions/build.xml b/build/tmpl/editions/build.xml
index b1ccd0fa82..3414055fcf 100644
--- a/build/tmpl/editions/build.xml
+++ b/build/tmpl/editions/build.xml
@@ -832,9 +832,17 @@
+
-
+
+
+
+
+
+
+
+
diff --git a/libraries/org.core4j_0.5/library.xml b/libraries/org.core4j_0.5/library.xml
new file mode 100644
index 0000000000..b39897c058
--- /dev/null
+++ b/libraries/org.core4j_0.5/library.xml
@@ -0,0 +1,19 @@
+
+ Core 4J
+ Core 4j Library used by odata4j
+ 0.5
+ 1
+ http://code.google.com/p/core4j/source/browse/
+ http://mvnrepository.com/artifact/org.core4j/core4j/0.5
+ Google Inc.
+
+
+
+ org.core4j
+ core4j
+
+
+
+
+
+
diff --git a/libraries/org.core4j_0.5/license.txt b/libraries/org.core4j_0.5/license.txt
new file mode 100644
index 0000000000..261eeb9e9f
--- /dev/null
+++ b/libraries/org.core4j_0.5/license.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/libraries/org.core4j_0.5/org.core4j-0.5.jar b/libraries/org.core4j_0.5/org.core4j-0.5.jar
new file mode 100644
index 0000000000..be8a11d638
Binary files /dev/null and b/libraries/org.core4j_0.5/org.core4j-0.5.jar differ
diff --git a/libraries/org.jvnet.mimepull_1.9.3/library.xml b/libraries/org.jvnet.mimepull_1.9.3/library.xml
new file mode 100644
index 0000000000..7645fbec61
--- /dev/null
+++ b/libraries/org.jvnet.mimepull_1.9.3/library.xml
@@ -0,0 +1,19 @@
+
+ MimePull Library
+ Mimepull Library used by restlet for batch operations
+ 1.9.3
+ 1
+ http://mimepull.java.net/
+ http://mvnrepository.com/artifact/org.jvnet.mimepull/mimepull/1.9.3
+ Oracle Inc.
+
+
+
+ org.jvnet.mimepull
+ mimepull
+
+
+
+
+
+
diff --git a/libraries/org.jvnet.mimepull_1.9.3/license.txt b/libraries/org.jvnet.mimepull_1.9.3/license.txt
new file mode 100644
index 0000000000..261eeb9e9f
--- /dev/null
+++ b/libraries/org.jvnet.mimepull_1.9.3/license.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/libraries/org.jvnet.mimepull_1.9.3/mimepull-1.9.3.jar b/libraries/org.jvnet.mimepull_1.9.3/mimepull-1.9.3.jar
new file mode 100644
index 0000000000..c3234556e0
Binary files /dev/null and b/libraries/org.jvnet.mimepull_1.9.3/mimepull-1.9.3.jar differ
diff --git a/modules/org.restlet.ext.crypto/src/META-INF/services/org.restlet.engine.security.AuthenticatorHelper b/modules/org.restlet.ext.crypto/src/META-INF/services/org.restlet.engine.security.AuthenticatorHelper
index c3ab215c04..e144058a66 100644
--- a/modules/org.restlet.ext.crypto/src/META-INF/services/org.restlet.engine.security.AuthenticatorHelper
+++ b/modules/org.restlet.ext.crypto/src/META-INF/services/org.restlet.engine.security.AuthenticatorHelper
@@ -3,3 +3,4 @@ org.restlet.ext.crypto.internal.HttpAwsQueryHelper
org.restlet.ext.crypto.internal.HttpDigestHelper
org.restlet.ext.crypto.internal.HttpAzureSharedKeyHelper
org.restlet.ext.crypto.internal.HttpAzureSharedKeyLiteHelper
+org.restlet.ext.crypto.internal.HttpNegotiateHelper
\ No newline at end of file
diff --git a/modules/org.restlet.ext.crypto/src/org/restlet/ext/crypto/internal/HttpNegotiateHelper.java b/modules/org.restlet.ext.crypto/src/org/restlet/ext/crypto/internal/HttpNegotiateHelper.java
new file mode 100644
index 0000000000..2845488432
--- /dev/null
+++ b/modules/org.restlet.ext.crypto/src/org/restlet/ext/crypto/internal/HttpNegotiateHelper.java
@@ -0,0 +1,184 @@
+/**
+ * Copyright 2005-2013 Restlet S.A.S.
+ *
+ * The contents of this file are subject to the terms of one of the following
+ * open source licenses: Apache 2.0 or LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL
+ * 1.0 (the "Licenses"). You can select the license that you prefer but you may
+ * not use this file except in compliance with one of these Licenses.
+ *
+ * You can obtain a copy of the Apache 2.0 license at
+ * http://www.opensource.org/licenses/apache-2.0
+ *
+ * You can obtain a copy of the LGPL 3.0 license at
+ * http://www.opensource.org/licenses/lgpl-3.0
+ *
+ * You can obtain a copy of the LGPL 2.1 license at
+ * http://www.opensource.org/licenses/lgpl-2.1
+ *
+ * You can obtain a copy of the CDDL 1.0 license at
+ * http://www.opensource.org/licenses/cddl1
+ *
+ * You can obtain a copy of the EPL 1.0 license at
+ * http://www.opensource.org/licenses/eclipse-1.0
+ *
+ * See the Licenses for the specific language governing permissions and
+ * limitations under the Licenses.
+ *
+ * Alternatively, you can obtain a royalty free commercial license with less
+ * limitations, transferable or non-transferable, directly at
+ * http://www.restlet.com/products/restlet-framework
+ *
+ * Restlet is a registered trademark of Restlet S.A.S.
+ */
+
+package org.restlet.ext.crypto.internal;
+
+import java.io.UnsupportedEncodingException;
+import java.util.logging.Level;
+
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.data.ChallengeResponse;
+import org.restlet.data.ChallengeScheme;
+import org.restlet.data.CookieSetting;
+import org.restlet.data.Form;
+import org.restlet.data.Header;
+import org.restlet.data.Reference;
+import org.restlet.data.Status;
+import org.restlet.engine.header.ChallengeWriter;
+import org.restlet.engine.header.CookieWriter;
+import org.restlet.engine.header.HeaderConstants;
+import org.restlet.engine.header.HeaderUtils;
+import org.restlet.engine.security.AuthenticatorHelper;
+import org.restlet.engine.util.Base64;
+import org.restlet.resource.ClientResource;
+import org.restlet.util.Series;
+
+/**
+ * Implements the HTTP Negotiate helper for form based authentication. It will
+ * submit the username/password passed as credentials from consumer to default
+ * action url. Once user is authenticated then we add the cookies sent by server
+ * to request object.
+ *
+ * @author Onkar Dhuri
+ */
+public class HttpNegotiateHelper extends AuthenticatorHelper {
+
+ /** The action url where form needs to submitted. */
+ public static String ACTION_URL = "/j_security_check";
+
+ /** The field name of username input box. */
+ public static String USERNAME = "j_username";
+
+ /** The field name of password input box. */
+ public static String PASSWORD = "j_password";
+
+ /**
+ * Constructor.
+ */
+ public HttpNegotiateHelper() {
+ super(ChallengeScheme.HTTP_NEGOTIATE, true, true);
+ }
+
+ /**
+ * This method submits the form to {ACTION_URL} as defined to authenticate
+ * the request.
+ * Once credentials are validated, the server will send out the 302 Response
+ * with "JSESSIONID" & "JSESSIONIDSSO" cookies.
+ * We set these cookies into request header for subsequent operations.
+ *
+ * @see org.restlet.engine.security.AuthenticatorHelper#formatResponse(org.restlet.engine.header.ChallengeWriter,
+ * org.restlet.data.ChallengeResponse, org.restlet.Request,
+ * org.restlet.util.Series)
+ *
+ */
+ @Override
+ public void formatResponse(ChallengeWriter cw, ChallengeResponse challenge,
+ Request request, Series httpHeaders) {
+ if (challenge == null) {
+ throw new RuntimeException(
+ "No challenge provided, unable to encode credentials");
+ } else {
+ /*
+ * Submit the form only if we dont have any cookies set in the request.
+ * For first /$metadata request, it wont have cookies, so it will submit the form and cookies are cached.
+ * Double check if cached cookies really has JSESSIONID/JSESSIONIDSSO, if not then submit the form again.
+ */
+ if(request.getCookies().size() == 0 ||
+ (request.getCookies().getFirst("JSESSIONID") == null || request.getCookies().getFirst("JSESSIONIDSSO") == null)){
+ Reference resourceRef = request.getResourceRef();
+ String relativeURL = resourceRef.toString().substring(0,
+ resourceRef.toString().lastIndexOf("/"));
+ ClientResource loginCr = new ClientResource(relativeURL
+ + ACTION_URL);
+ Form loginForm = new Form();
+ loginForm.add(USERNAME, challenge.getIdentifier());
+ loginForm.add(PASSWORD, new String(challenge.getSecret()));
+ loginCr.post(loginForm);
+ Response response = loginCr.getResponse();
+ // check if we get 302 response status; then only add the cookies
+ // else throw exception
+ if (response.getStatus().equals(Status.REDIRECTION_FOUND)
+ || response.getStatus()
+ .equals(Status.REDIRECTION_PERMANENT)) {
+ Series cookieSetting = loginCr
+ .getCookieSettings();
+ for (CookieSetting cs : cookieSetting) {
+ request.getCookies().add(cs.getName(), cs.getValue());
+ }
+ // finally add all the cookies in header
+ HeaderUtils.addHeader(HeaderConstants.HEADER_COOKIE,
+ CookieWriter.write(request.getCookies()), httpHeaders);
+ } else {
+ throw new RuntimeException(
+ "Can't authorize the request with passed credentials. "
+ + "Please check if you are passing correct credentials");
+ }
+ }
+ }
+ }
+
+ /**
+ * For "Negotiate" we are not currently using this API but we might use it
+ * in future if we need to set the credentials to ChallengeResponse
+ *
+ * @see org.restlet.engine.security.AuthenticatorHelper#parseResponse(org.restlet.data.ChallengeResponse,
+ * org.restlet.Request, org.restlet.util.Series)
+ *
+ */
+ @Override
+ public void parseResponse(ChallengeResponse challenge, Request request,
+ Series httpHeaders) {
+ try {
+ // Check if Negotiate auth header uses Base64 encoding
+ byte[] credentialsEncoded = Base64.decode(challenge.getRawValue());
+
+ if (credentialsEncoded == null) {
+ getLogger()
+ .info("Cannot decode credentials: "
+ + challenge.getRawValue());
+ }
+
+ String credentials = new String(credentialsEncoded, "ISO-8859-1");
+ int separator = credentials.indexOf(':');
+
+ if (separator == -1) {
+ // Log the blocking
+ getLogger().info(
+ "Invalid credentials given by client with IP: "
+ + ((request != null) ? request.getClientInfo()
+ .getAddress() : "?"));
+ } else {
+ challenge.setIdentifier(credentials.substring(0, separator));
+ challenge.setSecret(credentials.substring(separator + 1));
+ }
+ } catch (UnsupportedEncodingException e) {
+ getLogger().log(Level.INFO,
+ "Unsupported HTTP negotiate encoding error", e);
+ } catch (IllegalArgumentException e) {
+ getLogger().log(Level.INFO,
+ "Unable to decode the HTTP Negotiate credential", e);
+ }
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/module.xml b/modules/org.restlet.ext.odata/module.xml
index 0ba213f58a..bd33c7ceaa 100644
--- a/modules/org.restlet.ext.odata/module.xml
+++ b/modules/org.restlet.ext.odata/module.xml
@@ -13,6 +13,10 @@
+
+
+
+
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java
index 23091fa3ec..2590b2630f 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java
@@ -36,10 +36,20 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
-
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.commons.cli.BasicParser;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.restlet.data.ChallengeResponse;
+import org.restlet.data.ChallengeScheme;
import org.restlet.data.CharacterSet;
import org.restlet.data.MediaType;
import org.restlet.data.Reference;
@@ -66,311 +76,467 @@
*/
public class Generator {
- /**
- * Takes two (or three) parameters:
- *
- * The URI of the OData service
- * The output directory (optional, used the current directory by
- * default)
- * The name of the generated service class name (optional)
- *
- *
- * @param args
- * The list of arguments.
- */
- public static void main(String[] args) {
- System.out.println("---------------------------");
- System.out.println("OData client code generator");
- System.out.println("---------------------------");
- System.out.println("step 1 - check parameters");
-
- String errorMessage = null;
-
- if (args == null || args.length == 0) {
- errorMessage = "Missing mandatory argument: URI of the OData service.";
- }
-
- File outputDir = null;
-
- if (errorMessage == null) {
- if (args.length > 1) {
- outputDir = new File(args[1]);
- } else {
- try {
- outputDir = new File(".").getCanonicalFile();
- } catch (IOException e) {
- errorMessage = "Unable to get the target directory. "
- + e.getMessage();
- }
- }
-
- if (outputDir.exists()) {
- System.out.println("step 2 - check the ouput directory");
- if (!outputDir.isDirectory()) {
- errorMessage = outputDir.getPath()
- + " is not a valid directory.";
- }
-
- } else {
- try {
- System.out.println("step 2 - create the ouput directory");
- outputDir.mkdirs();
- } catch (Throwable e) {
- errorMessage = "Cannot create " + outputDir.getPath()
- + " due to: " + e.getMessage();
- }
- }
- }
- if (errorMessage == null) {
- System.out.println("step 3 - get the metadata descriptor");
- String dataServiceUri = null;
-
- if (args[0].endsWith("$metadata")) {
- dataServiceUri = args[0].substring(0, args[0].length() - 10);
- } else if (args[0].endsWith("/")) {
- dataServiceUri = args[0].substring(0, args[0].length() - 1);
- } else {
- dataServiceUri = args[0];
- }
-
- Service service = new Service(dataServiceUri);
- if (service.getMetadata() == null) {
- errorMessage = "Cannot retrieve the metadata.";
- } else {
- System.out.println("step 4 - generate source code");
- Generator svcUtil = null;
- if (args.length == 3) {
- svcUtil = new Generator(service.getServiceRef(), args[2]);
- } else {
- svcUtil = new Generator(service.getServiceRef());
- }
-
- try {
- svcUtil.generate(outputDir);
- System.out
- .print("The source code has been generated in directory: ");
- System.out.println(outputDir.getPath());
- } catch (Exception e) {
- errorMessage = "Cannot generate the source code in directory: "
- + outputDir.getPath();
- }
- }
- }
-
- if (errorMessage != null) {
- System.out.println("An error occurred: ");
- System.out.println(errorMessage);
- System.out.println();
- System.out
- .println("Please check that you provide the following parameters:");
- System.out.println(" - Valid URI for the remote service");
- System.out
- .println(" - Valid directory path where to generate the files");
- System.out
- .println(" - Valid name for the generated service class (optional)");
- }
- }
-
- /** The name of the service class (in case there is only one in the schema). */
- private String serviceClassName;
-
- /** The URI of the target data service. */
- private Reference serviceRef;
-
- /**
- * Constructor.
- *
- * @param serviceRef
- * The URI of the OData service.
- */
- public Generator(Reference serviceRef) {
- this(serviceRef, null);
- }
-
- /**
- * Constructor. The name of the service class can be provided if there is
- * only one service defined in the metadata.
- *
- * @param serviceRef
- * The URI of the OData service.
- * @param serviceClassName
- * The name of the service class (in case there is only one in
- * the metadata).
- */
- public Generator(Reference serviceRef, String serviceClassName) {
- super();
- this.serviceRef = serviceRef;
- if (serviceClassName != null) {
- this.serviceClassName = ReflectUtils.normalize(serviceClassName);
- this.serviceClassName = this.serviceClassName.substring(0, 1)
- .toUpperCase() + this.serviceClassName.substring(1);
- }
-
- }
-
- /**
- * Constructor.
- *
- * @param serviceUri
- * The URI of the OData service.
- */
- public Generator(String serviceUri) {
- this(serviceUri, null);
- }
-
- /**
- * Constructor. The name of the service class can be provided if there is
- * only one service defined in the metadata.
- *
- * @param serviceUri
- * The URI of the OData service.
- * @param serviceClassName
- * The name of the service class (in case there is only one in
- * the metadata).
- */
- public Generator(String serviceUri, String serviceClassName) {
- this(new Reference(serviceUri), serviceClassName);
- }
-
- /**
- * Generates the client code to the given output directory.
- *
- * @param outputDir
- * The output directory.
- * @throws Exception
- */
- public void generate(File outputDir) throws Exception {
- Service service = new Service(serviceRef);
- Metadata metadata = (Metadata) service.getMetadata();
- if (metadata == null) {
- throw new Exception("Can't get the metadata for this service: "
- + serviceRef);
- }
-
- Configuration fmc = new Configuration();
- fmc.setDefaultEncoding(CharacterSet.UTF_8.getName());
-
- // Generate classes
- String rootTemplates = "clap://class/org/restlet/ext/odata/internal/templates";
- Representation complexTmpl = new StringRepresentation(
- new ClientResource(rootTemplates + "/complexType.ftl").get()
- .getText());
- Representation entityTmpl = new StringRepresentation(
- new ClientResource(rootTemplates + "/entityType.ftl").get()
- .getText());
- Representation serviceTmpl = new StringRepresentation(
- new ClientResource(rootTemplates + "/service.ftl").get()
- .getText());
-
- for (Schema schema : metadata.getSchemas()) {
- if ((schema.getEntityTypes() != null && !schema.getEntityTypes()
- .isEmpty())
- || (schema.getComplexTypes() != null && !schema
- .getComplexTypes().isEmpty())) {
- String packageName = TypeUtils.getPackageName(schema);
- File packageDir = new File(outputDir, packageName.replace(".",
- System.getProperty("file.separator")));
- packageDir.mkdirs();
-
- // For each entity type
- for (EntityType type : schema.getEntityTypes()) {
- String className = type.getClassName();
- Map dataModel = new HashMap();
- dataModel.put("type", type);
- dataModel.put("schema", schema);
- dataModel.put("metadata", metadata);
- dataModel.put("className", className);
- dataModel.put("packageName", packageName);
-
- TemplateRepresentation templateRepresentation = new TemplateRepresentation(
- entityTmpl, fmc, dataModel, MediaType.TEXT_PLAIN);
- templateRepresentation.setCharacterSet(CharacterSet.UTF_8);
-
- // Write the template representation as a Java class
- OutputStream fos = new FileOutputStream(new File(
- packageDir, type.getClassName() + ".java"));
- templateRepresentation.write(fos);
- fos.flush();
- }
-
- for (ComplexType type : schema.getComplexTypes()) {
- String className = type.getClassName();
- Map dataModel = new HashMap();
- dataModel.put("type", type);
- dataModel.put("schema", schema);
- dataModel.put("metadata", metadata);
- dataModel.put("className", className);
- dataModel.put("packageName", packageName);
-
- TemplateRepresentation templateRepresentation = new TemplateRepresentation(
- complexTmpl, fmc, dataModel, MediaType.TEXT_PLAIN);
- templateRepresentation.setCharacterSet(CharacterSet.UTF_8);
-
- // Write the template representation as a Java class
- OutputStream fos = new FileOutputStream(new File(
- packageDir, type.getClassName() + ".java"));
- templateRepresentation.write(fos);
- fos.flush();
- }
- }
- }
- if (metadata.getContainers() != null
- && !metadata.getContainers().isEmpty()) {
- for (EntityContainer entityContainer : metadata.getContainers()) {
- Schema schema = entityContainer.getSchema();
- // Generate Service subclass
- StringBuffer className = new StringBuffer();
-
- if (serviceClassName != null) {
- // Try to use the Client preference
- if (entityContainer.isDefaultEntityContainer()) {
- className.append(serviceClassName);
- } else if (metadata.getContainers().size() == 1) {
- className.append(serviceClassName);
- } else {
- className.append(schema.getNamespace()
- .getNormalizedName().substring(0, 1)
- .toUpperCase());
- className.append(schema.getNamespace()
- .getNormalizedName().substring(1));
- className.append("Service");
- }
- } else {
- className.append(schema.getNamespace().getNormalizedName()
- .substring(0, 1).toUpperCase());
- className.append(schema.getNamespace().getNormalizedName()
- .substring(1));
- className.append("Service");
- }
-
- Map dataModel = new HashMap();
- dataModel.put("schema", schema);
- dataModel.put("metadata", metadata);
- dataModel.put("className", className);
- dataModel.put("dataServiceUri", this.serviceRef.getTargetRef());
- dataModel.put("entityContainer", entityContainer);
-
- TemplateRepresentation templateRepresentation = new TemplateRepresentation(
- serviceTmpl, fmc, dataModel, MediaType.TEXT_PLAIN);
- templateRepresentation.setCharacterSet(CharacterSet.UTF_8);
-
- // Write the template representation as a Java class
- OutputStream fos = new FileOutputStream(new File(outputDir,
- className + ".java"));
- templateRepresentation.write(fos);
- fos.flush();
- }
- }
- }
-
- /**
- * Generates the client code to the given output directory.
- *
- * @param outputDir
- * The output directory.
- * @throws Exception
- */
- public void generate(String outputDir) throws Exception {
- generate(new File(outputDir));
- }
+ /** The Constant SERVICE_URL. */
+ private final static String SERVICE_URL = "serviceUrl";
+
+ /** The Constant USERNAME. */
+ private final static String USERNAME = "userName";
+
+ /** The Constant PASSWORD. */
+ private final static String PASSWORD = "password";
+
+ /** The Constant CHALLENGE_SCHEME. */
+ private final static String CHALLENGE_SCHEME = "challengeScheme";
+
+ /** The Constant SERVICE_CLASSNAME. */
+ private final static String SERVICE_CLASSNAME = "serviceClassName";
+
+ /** The Constant SERVICE_CLASS_DIR. */
+ private final static String SERVICE_CLASS_DIR = "serviceClassDir";
+
+ /** The Constant ENTITY_CLASS_DIR. */
+ private final static String ENTITY_CLASS_DIR = "entityClassDir";
+
+ /** The URI of the target data service. */
+ private Reference serviceUrl;
+
+ /** The user name. */
+ private static String userName;
+
+ /** The password. */
+ private static String password;
+
+ /** The challenge scheme. */
+ private static ChallengeScheme challengeScheme;
+
+ /** The name of the service class (in case there is only one in the schema). */
+ private static String serviceClassName;
+
+ /** The entity pkg. */
+ private static String entityPkg;
+
+ /** The service pkg. */
+ private static String servicePkg;
+
+ /** The package dir where entity classes are generated. */
+ private static File packageDir;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger
+ .getLogger(Generator.class.getName());
+
+
+ /**
+ * Default Constructor.
+ *
+ * @param serviceRef
+ * The URI of the OData service.
+ */
+ public Generator(Reference serviceRef) {
+ this(serviceRef, null);
+ }
+
+ /**
+ * Constructor. The name of the service class can be provided if there is
+ * only one service defined in the metadata.
+ *
+ * @param serviceRef
+ * The URI of the OData service.
+ * @param serviceClassName
+ * The name of the service class (in case there is only one in
+ * the metadata).
+ */
+ public Generator(Reference serviceRef, String serviceClassName) {
+ super();
+ this.serviceUrl = serviceRef;
+ if (serviceClassName != null) {
+ Generator.serviceClassName = ReflectUtils.normalize(serviceClassName);
+ Generator.serviceClassName = Generator.serviceClassName.substring(0, 1)
+ .toUpperCase() + Generator.serviceClassName.substring(1);
+ }
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param serviceUri
+ * The URI of the OData service.
+ */
+ public Generator(String serviceUri) {
+ this(serviceUri, null);
+ }
+
+ /**
+ * Constructor. The name of the service class can be provided if there is
+ * only one service defined in the metadata.
+ *
+ * @param serviceUri
+ * The URI of the OData service.
+ * @param serviceClassName
+ * The name of the service class (in case there is only one in
+ * the metadata).
+ */
+ public Generator(String serviceUri, String serviceClassName) {
+ this(new Reference(serviceUri), serviceClassName);
+ }
+
+
+ /**
+ * Takes seven parameters:
+ *
+ * The URI of the OData service
+ * Username to access OData service
+ * Password to access OData service
+ * ChallangeScheme - Possible values HTTP_BASIC, HTTP_NEGOTIATE, if not provided then HTTP_BASIC will be used as default.
+ * Service class name
+ * The output directory for Service class generation (For example : src/com/ow/service),
+ * if no directory is provided class will be generated in the default package.
+ * The output directory for Entity class generation (For example : src/com/ow/entities),
+ * if no directory is provided schema name will be used as default package.
+ *
+ *
+ * @param args
+ * The list of arguments.
+ */
+ public static void main(String[] args) {
+
+ System.out.println("---------------------------");
+ System.out.println("OData client code generator");
+ System.out.println("---------------------------");
+ System.out.println("step 1 - check parameters");
+
+ String errorMessage = null;
+ File entityClassDir = null;
+ File serviceDir = null;
+
+ final CommandLineParser parser = new BasicParser();
+ final Options options = new Options();
+ setCommandLineOptions(options);
+
+ CommandLine commandLine = null;
+ // try to parse and validate the passed arguments using apache commons cli.
+ try {
+ commandLine = parser.parse(options, args);
+ } catch (ParseException e) {
+ System.out.println(e.getMessage());
+ printUsage(options);
+ }
+
+ userName = getOption(USERNAME, commandLine);
+ password = getOption(PASSWORD, commandLine);
+ challengeScheme = (getOption(CHALLENGE_SCHEME, commandLine) == null ? null
+ : ChallengeScheme.valueOf(getOption(CHALLENGE_SCHEME, commandLine)));
+
+ serviceClassName = getOption(SERVICE_CLASSNAME, commandLine);
+
+ if (getOption(SERVICE_CLASS_DIR, commandLine) != null) {
+ serviceDir = new File(getOption(SERVICE_CLASS_DIR, commandLine));
+ servicePkg = getOption(SERVICE_CLASS_DIR, commandLine).substring(4, getOption(SERVICE_CLASS_DIR, commandLine).length());
+ } else {
+ try {
+ serviceDir = new File(".").getCanonicalFile();
+ // set package name to blank if user did not pass this option
+ servicePkg = "";
+ } catch (IOException e) {
+ errorMessage = "Unable to get the target directory for service generation. "
+ + e.getMessage();
+ }
+ }
+
+ if (serviceDir.exists()) {
+ System.out.println("step 2 - check the service directory");
+ if (!serviceDir.isDirectory()) {
+ errorMessage = serviceDir.getPath()
+ + " is not a valid directory.";
+ }
+
+ } else {
+ try {
+ System.out.println("step 2 - create the service directory");
+ serviceDir.mkdirs();
+ } catch (Throwable e) {
+ errorMessage = "Cannot create " + serviceDir.getPath()
+ + " due to: " + e.getMessage();
+ }
+ }
+
+ if (getOption(ENTITY_CLASS_DIR, commandLine) != null) {
+ entityClassDir = new File(getOption(ENTITY_CLASS_DIR, commandLine));
+ entityPkg = getOption(ENTITY_CLASS_DIR, commandLine).substring(4, getOption(ENTITY_CLASS_DIR, commandLine).length());
+ }
+
+ if (errorMessage == null) {
+ System.out.println("step 3 - get the metadata descriptor");
+ String dataServiceUri = getOption(SERVICE_URL, commandLine);
+
+ if (dataServiceUri.endsWith("$metadata")) {
+ dataServiceUri = dataServiceUri.substring(0, dataServiceUri.length() - 10);
+ } else if (dataServiceUri.endsWith("/")) {
+ dataServiceUri = dataServiceUri.substring(0, dataServiceUri.length() - 1);
+ }
+
+ Service service = new Service(dataServiceUri);
+ if(challengeScheme != null && userName != null && password != null){
+ service.setCredentials(new ChallengeResponse(challengeScheme, userName,
+ password));
+ }
+ if (service.getMetadata() == null) {
+ errorMessage = "Cannot retrieve the metadata.";
+ } else {
+ System.out.println("step 4 - generate source code");
+ Generator svcUtil = new Generator(service.getServiceRef());
+
+ try {
+ svcUtil.generate(entityClassDir, serviceDir);
+ System.out.print("The source code has been generated in directory: ");
+ System.out.println(packageDir.getPath());
+ } catch (Exception e) {
+ errorMessage = "Cannot generate the source code in directory: "
+ + packageDir.getPath();
+ }
+ }
+ } else{
+ LOGGER.log(Level.SEVERE,errorMessage);
+ }
+ }
+
+ /**
+ * Sets the command line options.
+ *
+ * @param options the new command line options
+ */
+ private static void setCommandLineOptions(Options options) {
+
+ /** Creates an Option for serviceUrl using the specified parameters */
+ Option serviceUrlOption = new Option("su", SERVICE_URL, true, "The URI of the OData service");
+ serviceUrlOption.setRequired(true);
+ options.addOption(serviceUrlOption);
+
+ /** Creates an Option for userName */
+ Option userNameOption = new Option("ur", USERNAME, true, "Username to access OData service");
+ options.addOption(userNameOption);
+
+ /** Creates an Option for password */
+ Option passwordOption = new Option("pw", PASSWORD, true, "Password to access OData service");
+ options.addOption(passwordOption);
+
+ /** Creates an Option for challangeScheme */
+ Option challangeSchemeOption = new Option("cs", CHALLENGE_SCHEME, true, "ChallengeScheme - Possible values HTTP_BASIC, HTTP_NEGOTIATE, if not provided then no authentication will be used");
+ options.addOption(challangeSchemeOption);
+
+ /** Creates an Option for sreviceClassName */
+ Option sreviceClassNameOption = new Option("sc", SERVICE_CLASSNAME, true, "Service class name");
+ options.addOption(sreviceClassNameOption);
+
+ /** Creates an Option for serviceClassDir */
+ Option serviceClassDirOption = new Option("sd", SERVICE_CLASS_DIR, true, "The output directory for Service class generation (For example : src/com/edm/entities)");
+ options.addOption(serviceClassDirOption);
+
+ /** Creates an Option for entityClassDir */
+ Option entityClassDirOption = new Option("ed", ENTITY_CLASS_DIR, true, "The output directory for Entity class generation (For example : src/com/edm/entities");
+ options.addOption(entityClassDirOption);
+
+ }
+
+ /**
+ * Prints the usage.
+ *
+ * @param options the options
+ */
+ public static void printUsage(Options options)
+ {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("available options as follow : ", options );
+ System.exit(1);
+ }
+
+ /**
+ * To retrieve argument for the Option.
+ *
+ * @param option the option
+ * @param commandLine the command line
+ * @return the option
+ */
+ public static String getOption(final String option, final CommandLine commandLine) {
+
+ if (commandLine.hasOption(option)) {
+ return commandLine.getOptionValue(option);
+ }
+
+ return null;
+ }
+
+ /**
+ * Generates the client code to the given output directory.
+ *
+ * @param outputDir The output directory.
+ * @param serviceDir the service dir
+ * @throws Exception the exception
+ */
+ public void generate(File outputDir, File serviceDir) throws Exception {
+ Service service = new Service(serviceUrl);
+ if(challengeScheme != null && userName != null && password != null){
+ service.setCredentials(new ChallengeResponse(challengeScheme, userName,
+ password));
+ }
+ Configuration fmc = new Configuration();
+ fmc.setDefaultEncoding(CharacterSet.UTF_8.getName());
+
+ // Generate classes
+ String rootTemplates = "clap://class/org/restlet/ext/odata/internal/templates";
+ Representation complexTmpl = new StringRepresentation(
+ new ClientResource(rootTemplates + "/complexType.ftl").get()
+ .getText());
+ Representation entityTmpl = new StringRepresentation(
+ new ClientResource(rootTemplates + "/entityType.ftl").get()
+ .getText());
+ Representation serviceTmpl = new StringRepresentation(
+ new ClientResource(rootTemplates + "/service.ftl").get()
+ .getText());
+
+ Metadata metadata = (Metadata) service.getMetadata();
+ for (Schema schema : metadata.getSchemas()) {
+ if ((schema.getEntityTypes() != null && !schema.getEntityTypes()
+ .isEmpty())
+ || (schema.getComplexTypes() != null && !schema
+ .getComplexTypes().isEmpty())) {
+
+ packageDir = outputDir != null ? outputDir : new File(
+ TypeUtils.getPackageName(schema));
+ packageDir.mkdirs();
+
+ String packageName = outputDir != null ? (entityPkg.replace(
+ "/", ".")) : TypeUtils.getPackageName(schema);
+ // For each entity type
+ for (EntityType type : schema.getEntityTypes()) {
+ String className = type.getClassName();
+ Map dataModel = new HashMap();
+ dataModel.put("type", type);
+ dataModel.put("schema", schema);
+ dataModel.put("metadata", metadata);
+ dataModel.put("className", className);
+ dataModel.put("packageName", packageName);
+
+ try {
+ TemplateRepresentation templateRepresentation = new TemplateRepresentation(
+ entityTmpl, fmc, dataModel,
+ MediaType.TEXT_PLAIN);
+ templateRepresentation
+ .setCharacterSet(CharacterSet.UTF_8);
+
+ // Write the template representation as a Java class
+ templateRepresentation.write(new FileOutputStream(
+ new File(packageDir, type.getClassName()
+ + ".java")));
+ } catch (Exception e) {
+ String errormsg = "Exception Occurred in generating entity type for - "
+ + type.getClassName();
+ LOGGER.log(Level.SEVERE,errormsg);
+ }
+
+ }
+
+ for (ComplexType type : schema.getComplexTypes()) {
+ String className = type.getClassName();
+ Map dataModel = new HashMap();
+ dataModel.put("type", type);
+ dataModel.put("schema", schema);
+ dataModel.put("metadata", metadata);
+ dataModel.put("className", className);
+ dataModel.put("packageName", packageName);
+
+ try {
+ TemplateRepresentation templateRepresentation = new TemplateRepresentation(
+ complexTmpl, fmc, dataModel,
+ MediaType.TEXT_PLAIN);
+
+ templateRepresentation
+ .setCharacterSet(CharacterSet.UTF_8);
+
+ // Write the template representation as a Java class
+ templateRepresentation.write(new FileOutputStream(
+ new File(packageDir, type.getClassName()
+ + ".java")));
+ } catch (Exception e) {
+ String errormsg = "Exception Occurred in generating complex type for - "
+ + type.getClassName();
+ LOGGER.log(Level.SEVERE,errormsg);
+ }
+ }
+ }
+ }
+
+ if (metadata.getContainers() != null
+ && !metadata.getContainers().isEmpty()) {
+ for (EntityContainer entityContainer : metadata.getContainers()) {
+ Schema schema = entityContainer.getSchema();
+ // Generate Service subclass
+ StringBuffer className = new StringBuffer();
+ if (serviceClassName != null) {
+ // Try to use the Client preference
+ if (entityContainer.isDefaultEntityContainer()) {
+ className.append(serviceClassName);
+ } else if (metadata.getContainers().size() == 1) {
+ className.append(serviceClassName);
+ } else {
+ className.append(schema.getNamespace()
+ .getNormalizedName().substring(0, 1)
+ .toUpperCase());
+ className.append(schema.getNamespace()
+ .getNormalizedName().substring(1));
+ className.append("Service");
+ }
+ } else {
+ className.append(schema.getNamespace().getNormalizedName()
+ .substring(0, 1).toUpperCase());
+ className.append(schema.getNamespace().getNormalizedName()
+ .substring(1));
+ className.append("Service");
+ }
+
+ String packageName = outputDir != null ? (servicePkg.replace(
+ "/", ".")) : TypeUtils.getPackageName(schema);
+ String entityClassPkg = outputDir != null ? (entityPkg.replace("/", ".")) : TypeUtils
+ .getPackageName(schema);
+ Map dataModel = new HashMap();
+ dataModel.put("schema", schema);
+ dataModel.put("metadata", metadata);
+ dataModel.put("className", className);
+ dataModel.put(CHALLENGE_SCHEME, challengeScheme != null ? "ChallengeScheme."+challengeScheme.getName() : null);
+ dataModel.put(USERNAME, userName);
+ dataModel.put(PASSWORD, password);
+ dataModel.put("dataServiceUri", service.getServiceRef()
+ .getTargetRef());
+ dataModel.put("entityContainer", entityContainer);
+ dataModel.put("servicePkg", servicePkg.replace("/", "."));
+ dataModel.put("entityClassPkg", entityClassPkg);
+ dataModel.put("packageName", packageName);
+
+ try {
+ TemplateRepresentation templateRepresentation = new TemplateRepresentation(
+ serviceTmpl, fmc, dataModel, MediaType.TEXT_PLAIN);
+ templateRepresentation.setCharacterSet(CharacterSet.UTF_8);
+
+ // Write the template representation as a Java class
+ templateRepresentation.write(new FileOutputStream(new File(
+ serviceDir, className + ".java")));
+ } catch (Exception e) {
+ String errormsg = "Exception Occurred in generating Service class for - "
+ + className;
+ LOGGER.log(Level.SEVERE,errormsg);
+ }
+ }
+ }
+ }
+
+ /**
+ * Generates the client code to the given output directory.
+ *
+ * @param outputDir The output directory.
+ * @throws Exception the exception
+ */
+ public void generate(String outputDir) throws Exception {
+ generate(new File(outputDir), new File(outputDir));
+ }
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Query.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Query.java
index ada2eed62e..89b3dc5ecc 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Query.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Query.java
@@ -51,6 +51,7 @@
import org.restlet.ext.odata.internal.FeedContentHandler;
import org.restlet.ext.odata.internal.edm.EntityType;
import org.restlet.ext.odata.internal.edm.Metadata;
+import org.restlet.ext.odata.xml.AtomFeedHandler;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ClientResource;
@@ -368,23 +369,15 @@ public void execute() throws Exception {
// Guess the type of query based on the URI structure
switch (guessType(targetUri)) {
case TYPE_ENTITY_SET:
- FeedContentHandler feedContentHandler = new FeedContentHandler(
- entityClass, entityType, metadata, getLogger());
- setFeed(new Feed(result, feedContentHandler));
- this.count = feedContentHandler.getCount();
- this.entities = feedContentHandler.getEntities();
- break;
case TYPE_ENTITY:
- EntryContentHandler entryContentHandler = new EntryContentHandler(
- entityClass, entityType, metadata, getLogger());
Feed feed = new Feed();
- feed.getEntries().add(
- new Entry(result, entryContentHandler));
- setFeed(feed);
- entities = new ArrayList();
- if (entryContentHandler.getEntity() != null) {
- entities.add(entryContentHandler.getEntity());
- }
+ AtomFeedHandler feedHandler = new AtomFeedHandler(entityType.getName(), entityType, entityClass, metadata);
+ ///AtomFeedCursorHandler feedHandler = new AtomFeedCursorHandler(entityType.getName(), entityType, entityClass);
+ feedHandler.setFeed(feed);
+ feedHandler.parse(result.getReader());
+ this.setFeed(feed);
+ this.count = -1;// no need to set as we send $count request later
+ this.entities = feedHandler.getEntities();
break;
case TYPE_UNKNOWN:
// Guess the type of query based on the returned
@@ -394,13 +387,13 @@ public void execute() throws Exception {
String string = rep.getText().substring(0,
Math.min(100, rep.getText().length()));
if (string.contains("(
+ FeedContentHandler feedContentHandler = new FeedContentHandler(
entityClass, entityType, metadata, getLogger());
setFeed(new Feed(rep, feedContentHandler));
this.count = feedContentHandler.getCount();
this.entities = feedContentHandler.getEntities();
} else if (string.contains("(
+ EntryContentHandler entryContentHandler = new EntryContentHandler(
entityClass, entityType, metadata, getLogger());
feed = new Feed();
feed.getEntries().add(
@@ -430,6 +423,19 @@ public void execute() throws Exception {
}
}
+
+ /**
+ * Gets the query client resource,used in the GetEntityRequest for Batch execution.
+ *
+ * @return the query client resource
+ */
+ public ClientResource getQueryClientResource() {
+ String targetUri = createTargetUri();
+ ClientResource resource = service.createResource(new Reference(
+ targetUri));
+ return resource;
+ }
+
/**
* Creates a new Query with the $expand option set in the URI generated
* by the returned query.
@@ -777,4 +783,11 @@ public Query skipToken(String token) {
public Query top(int rowsCount) {
return addParameter("$top", Integer.toString(rowsCount));
}
+
+ /**
+ * @return
+ */
+ public Class> getEntityClass() {
+ return entityClass;
+ }
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java
index 3012ae3390..7db4a0ff01 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java
@@ -35,11 +35,15 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -49,6 +53,7 @@
import org.restlet.Response;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.CharacterSet;
+import org.restlet.data.Cookie;
import org.restlet.data.Header;
import org.restlet.data.MediaType;
import org.restlet.data.Parameter;
@@ -58,12 +63,10 @@
import org.restlet.data.Tag;
import org.restlet.engine.header.HeaderConstants;
import org.restlet.engine.header.HeaderReader;
+import org.restlet.engine.header.HeaderUtils;
import org.restlet.ext.atom.Content;
import org.restlet.ext.atom.Entry;
-import org.restlet.ext.atom.Feed;
-import org.restlet.ext.atom.Link;
-import org.restlet.ext.atom.Relation;
-import org.restlet.ext.odata.internal.EntryContentHandler;
+import org.restlet.ext.odata.batch.util.RestletBatchRequestHelper;
import org.restlet.ext.odata.internal.edm.AssociationEnd;
import org.restlet.ext.odata.internal.edm.ComplexProperty;
import org.restlet.ext.odata.internal.edm.EntityContainer;
@@ -73,9 +76,13 @@
import org.restlet.ext.odata.internal.edm.Property;
import org.restlet.ext.odata.internal.edm.TypeUtils;
import org.restlet.ext.odata.internal.reflect.ReflectUtils;
+import org.restlet.ext.odata.streaming.StreamReference;
+import org.restlet.ext.odata.validation.annotation.SystemGenerated;
+import org.restlet.ext.odata.xml.AtomFeedHandler;
import org.restlet.ext.xml.DomRepresentation;
import org.restlet.ext.xml.SaxRepresentation;
import org.restlet.ext.xml.XmlWriter;
+import org.restlet.ext.xml.format.XmlFormatParser;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ClientResource;
@@ -129,7 +136,13 @@ public class Service {
/** The internal logger. */
private Logger logger;
-
+
+ private String slug = "";
+
+ /**
+ * add Query parameter in request header for each call.
+ */
+ private Map parameters;
/**
* The maximum version of the OData protocol extensions the client can
* accept in a response.
@@ -148,6 +161,18 @@ public class Service {
/** The reference of the WCF service. */
private Reference serviceRef;
+ /** The content type. */
+ private String contentType;
+
+ /** The isUpdateStreamData used to decide update operation on stream. */
+ private boolean isUpdateStreamData;
+
+ /** List of cookies used to cache the cookies sent from server. */
+ List cookies;
+
+ /** The isPostRequest used to differentiate POST request. */
+ private boolean isPostRequest;
+
/**
* Constructor.
*
@@ -199,6 +224,8 @@ public Service(String serviceUri) {
/**
* Adds an entity to an entity set.
+ * @param
+ * @param
*
* @param entitySetName
* The path of the entity set relatively to the service URI.
@@ -206,41 +233,103 @@ public Service(String serviceUri) {
* The entity to put.
* @throws Exception
*/
- public void addEntity(String entitySetName, Object entity) throws Exception {
- if (entity != null) {
- Entry entry = toEntry(entity);
-
- ClientResource resource = createResource(entitySetName);
- if (getMetadata() == null) {
- throw new Exception("Can't add entity to this entity set "
- + resource.getReference()
- + " due to the lack of the service's metadata.");
- }
-
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- entry.write(baos);
- baos.flush();
- StringRepresentation r = new StringRepresentation(
- baos.toString(), MediaType.APPLICATION_ATOM);
- Representation rep = resource.post(r);
- EntryContentHandler> entryContentHandler = new EntryContentHandler(
- entity.getClass(), (Metadata) getMetadata(),
- getLogger());
- Feed feed = new Feed();
- feed.getEntries().add(new Entry(rep, entryContentHandler));
- } catch (ResourceException re) {
- throw new ResourceException(re.getStatus(),
- "Can't add entity to this entity set "
- + resource.getReference());
- } finally {
- this.latestRequest = resource.getRequest();
- this.latestResponse = resource.getResponse();
- }
- }
- }
-
- /**
+ public T addEntity(String entitySetName, Object entity) throws Exception {
+ if (entity != null) {
+ isPostRequest = Boolean.TRUE;
+ Metadata metadata = (Metadata) getMetadata();
+ EntityType type = metadata.getEntityType(entity.getClass());
+ ClientResource resource = createResource(entitySetName);
+ Representation rep = null;
+ try {
+ if (type.isBlob()) { // entity type is set to BLOB if hasStream property of an entity is true.
+
+ InputStream inputStream = this.handleStreamingWithSlug(entity, type);
+ if (getMetadata() == null) {
+ throw new Exception("Can't add entity to this entity set " + resource.getReference()
+ + " due to the lack of the service's metadata.");
+ }
+ //post the inputstream with slug header.
+ rep = resource.post(inputStream, slug, contentType);
+
+ AtomFeedHandler feedHandler = new AtomFeedHandler(type.getName(), type, entity.getClass(), metadata);
+ T newEntity = RestletBatchRequestHelper.getEntity(rep, feedHandler);
+ this.merge(entity, feedHandler.getFeed().getEntries().get(0).getId()); //merge the remaining properties using merge request.
+ return newEntity;
+ } else {
+ if (getMetadata() == null) {
+ throw new Exception("Can't add entity to this entity set " + resource.getReference()
+ + " due to the lack of the service's metadata.");
+ }
+ Entry entry = toEntry(entity);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ entry.write(baos);
+ baos.flush();
+ StringRepresentation r = new StringRepresentation(baos.toString(), MediaType.APPLICATION_ATOM);
+ rep = resource.post(r);
+ // parse the response to populate the newly created entity object
+
+ AtomFeedHandler feedHandler = new AtomFeedHandler(type.getName(), type, entity.getClass(), metadata);
+ T newEntity = RestletBatchRequestHelper.getEntity(rep, feedHandler);
+ return newEntity;
+ }
+ } catch (ResourceException re) {
+ throw new ResourceException(re.getStatus(), "Can't add entity to this entity set "
+ + resource.getReference());
+ } catch (Exception e) {
+ getLogger().log(Level.WARNING,
+ "Can't add the entity : " + " due to " + e.getMessage());
+ }finally {
+ isPostRequest = Boolean.FALSE;
+ this.latestRequest = resource.getRequest();
+ this.latestResponse = resource.getResponse();
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Method to handle Streaming data for create/update operation.
+ * It also creates slug header which we need for creating request headers for MLE.
+ * @param entity
+ * @param type
+ * @return
+ * @throws Exception
+ */
+ private InputStream handleStreamingWithSlug(Object entity, EntityType type) throws Exception {
+ List properties = type.getProperties();
+ Iterator iterator = properties.iterator();
+ InputStream inputStream = null;
+ slug="";
+ // Create the SLUG header for Streaming.
+ // As streaming entity requires mandatory fields to be passed as slug header.
+ // Request body contains only stream data. Slug header contains mandatory fields like PK.
+ while (iterator.hasNext()) {
+ Property prop = iterator.next();
+ if (!prop.isNullable()) {
+ Object propertyObject = ReflectUtils.getPropertyObject(entity, prop.getNormalizedName());
+ String propName = prop.getName() + "=" + propertyObject.toString();
+ if (slug.isEmpty()) {
+ slug = propName;
+ } else {
+ slug = slug + "," + propName;
+ }
+ } else {
+ if (prop.getType().getName().contains("Stream")) { // find the streaming property from entity and assign stream value to it.
+ Object propertyObject = ReflectUtils.invokeGetter(entity, prop.getNormalizedName());
+ if(null!= propertyObject){
+ StreamReference streamReference = (StreamReference) propertyObject;
+ inputStream = streamReference.getInputStream();
+ contentType = streamReference.getContentType();
+ isUpdateStreamData = streamReference.isUpdateStreamData();
+ }
+ }
+ }
+ }
+ return inputStream;
+ }
+
+ /**
* Adds an association between the source and the target entity via the
* given property name.
*
@@ -280,7 +369,7 @@ public Query createQuery(String subpath, Class entityClass) {
/**
* Returns an instance of {@link ClientResource} given an absolute
* reference. This resource is completed with the service credentials. This
- * method can be overriden in order to complete the sent requests.
+ * method can be overridden in order to complete the sent requests.
*
* @param reference
* The reference of the target resource.
@@ -293,23 +382,41 @@ public ClientResource createResource(Reference reference) {
// We provide our own cient connector.
resource.setNext(clientConnector);
}
+
+ // add the cached cookies to request to prevent submitting the form in form based auth.
+ if(this.cookies != null){
+ resource.getRequest().getCookies().addAll(this.cookies);
+ }
resource.setChallengeResponse(getCredentials());
-
+ Series headers = new Series(Header.class);
if (getClientVersion() != null || getMaxClientVersion() != null) {
- Series headers = new Series(Header.class);
-
+
if (getClientVersion() != null) {
headers.add("DataServiceVersion", getClientVersion());
}
if (getMaxClientVersion() != null) {
headers.add("MaxDataServiceVersion", getMaxClientVersion());
- }
-
- resource.setAttribute(HeaderConstants.ATTRIBUTE_HEADERS, headers);
+ }
+
}
-
+
+ /*
+ * Check if query parameter map is not null and not empty, add all the
+ * Query parameters in request as a header.
+ */
+ if (getParameter() != null && !getParameter().isEmpty()) {
+ Iterator> iterator = getParameter()
+ .entrySet().iterator();
+ while (iterator.hasNext()) {
+ java.util.Map.Entry entry = iterator.next();
+ headers.add(entry.getKey(), entry.getValue());
+ }
+
+ }
+ resource.setAttribute(HeaderConstants.ATTRIBUTE_HEADERS, headers);
+
return resource;
}
@@ -475,7 +582,7 @@ public String getMaxClientVersion() {
*
* @return The metadata document related to the current service.
*/
- protected Object getMetadata() {
+ public Object getMetadata() {
if (metadata == null) {
ClientResource resource = createResource("$metadata");
@@ -485,6 +592,14 @@ protected Object getMetadata() {
"Get the metadata for " + getServiceRef() + " at "
+ resource.getReference());
Representation rep = resource.get(MediaType.APPLICATION_XML);
+ // after metadata request is handled by submitting the form, get the cookies from response and cache it.
+ Series responseCookies = resource.getResponse().getRequest().getCookies();
+ if(responseCookies != null){
+ if(this.cookies == null){
+ this.cookies = new ArrayList();
+ }
+ this.cookies.addAll(responseCookies);
+ }
this.metadata = new Metadata(rep, resource.getReference());
} catch (ResourceException e) {
getLogger().log(
@@ -850,18 +965,51 @@ public Representation invokeComplex(String service,
if (function != null) {
ClientResource resource = createResource(service);
- resource.setMethod(function.getMethod());
+ if(function.getMethod() !=null){
+ resource.setMethod(function.getMethod());
+ }
if (parameters != null) {
- for (org.restlet.ext.odata.internal.edm.Parameter parameter : function
- .getParameters()) {
- resource.getReference().addQueryParameter(
- parameter.getName(),
- TypeUtils.getLiteralForm(parameters
- .getFirstValue(parameter.getName()),
- parameter.getType()));
- }
+ // if this is GET/DELETE method then send the paramenters in query string
+ if(resource.getMethod().equals(new org.restlet.data.Method("GET")) || resource.getMethod().equals(new org.restlet.data.Method("DELETE"))){
+ for (org.restlet.ext.odata.internal.edm.Parameter parameter : function
+ .getParameters()) {
+ resource.getReference().addQueryParameter(
+ parameter.getName(),
+ TypeUtils.getLiteralForm(parameters
+ .getFirstValue(parameter.getName()),
+ parameter.getType()));
+ }
+ }else{
+ StringBuilder sb = new StringBuilder();
+ sb.append("{"+"\n");
+ String json ="";
+ int noOfParameters=0;
+ for (Parameter parameter : parameters) {
+ noOfParameters++;
+ sb.append("\"").append(parameter.getName()).append("\"").append(":");
+ for (org.restlet.ext.odata.internal.edm.Parameter edmParameter : function.getParameters()) {
+ if(parameter.getName().equalsIgnoreCase(edmParameter.getName())){
+ if(edmParameter.getType().contains("String")){
+ json = "\"" + parameter.getValue()+ "\"";
+ }else if(edmParameter.getType().contains("Collection")){
+ json = parameter.getValue();
+ }else{
+ json = parameter.getValue();
+ }
+ sb.append(json);
+ if(noOfParameters!=parameters.size()){
+ sb.append(",");
+ }
+ }
+ }
+ }
+ sb.append("\n"+"}");
+ Series headerSeries = new Series(Header.class);
+ resource.getRequest().setEntity(sb.toString(), MediaType.APPLICATION_JSON);
+ HeaderUtils.addHeader(HeaderConstants.HEADER_ACCEPT,MediaType.APPLICATION_ATOM.getName(),headerSeries);
+ resource.setAttribute(HeaderConstants.ATTRIBUTE_HEADERS, headerSeries);
+ }
}
-
result = resource.handle();
this.latestRequest = resource.getRequest();
this.latestResponse = resource.getResponse();
@@ -1132,6 +1280,8 @@ private void write(XmlWriter writer, Object entity,
AttributesImpl nullAttrs) throws SAXException {
for (Field field : entity.getClass()
.getDeclaredFields()) {
+ SystemGenerated systemGeneratedAnnotation = field
+ .getAnnotation(SystemGenerated.class);
String getter = "get"
+ field.getName().substring(0, 1)
.toUpperCase()
@@ -1139,12 +1289,94 @@ private void write(XmlWriter writer, Object entity,
Property prop = ((Metadata) getMetadata())
.getProperty(entity, field.getName());
- if (prop != null) {
+ if (prop != null && systemGeneratedAnnotation == null && isPostRequest) {
+ writeProperty(writer, entity, prop, getter,
+ nullAttrs);
+ }
+ else if (prop != null && !isPostRequest) {
writeProperty(writer, entity, prop, getter,
nullAttrs);
}
}
}
+
+ /**
+ * Write collection property element.
+ *
+ * @param writer the writer
+ * @param entity the entity
+ * @param value the value
+ * @param prop the prop
+ * @param nullAttrs the null attrs
+ * @throws SAXException the SAX exception
+ */
+ private void writeCollectionProperty(XmlWriter writer, Object entity, Object value, Property prop, AttributesImpl nullAttrs) throws SAXException {
+ if (value instanceof List) {
+ try {
+ Field field = entity.getClass().getDeclaredField(
+ prop.getName());
+ if (field.getGenericType() instanceof ParameterizedType) {
+ // determine what type of collection it is
+ ParameterizedType listType = (ParameterizedType) field
+ .getGenericType();
+ Class> listClass = (Class>) listType
+ .getActualTypeArguments()[0]; // get the parameterized class
+ String mType = null;
+ boolean isPrimitiveCollection = false;
+ AttributesImpl typeAttr = new AttributesImpl();
+ if(listClass.getName().toLowerCase().startsWith("java")){ // collection of primitives
+ mType = "Collection("+ TypeUtils.toEdmType(listClass.getName()) + ")";
+ isPrimitiveCollection = true;
+ }else{ // collection of complex
+ String[] className = listClass.getName().split("\\.");
+ mType = "Collection("+ className[0].toUpperCase() + "." + className[1] + ")";
+ }
+ List> obj = (List>) value;
+ // write collection property tag
+ typeAttr.addAttribute(
+ WCF_DATASERVICES_METADATA_NAMESPACE,
+ "type", "type", "string", mType);
+ if(obj.size() == 0){
+ typeAttr.addAttribute(
+ WCF_DATASERVICES_METADATA_NAMESPACE,
+ "null", null, "boolean", "true");
+ }
+ writer.startElement(
+ WCF_DATASERVICES_NAMESPACE,
+ prop.getName(), prop.getName(),
+ typeAttr);
+ // write element tags
+ for (Object object : obj) {
+ if(isPrimitiveCollection){
+ if(object.toString().length()>0){
+ writer.dataElement(WCF_DATASERVICES_NAMESPACE, XmlFormatParser.DATASERVICES_ELEMENT.getLocalPart(), object.toString());
+ }else{
+ writer.emptyElement(
+ WCF_DATASERVICES_NAMESPACE,
+ XmlFormatParser.DATASERVICES_ELEMENT.getLocalPart(), XmlFormatParser.DATASERVICES_ELEMENT.getLocalPart(),
+ nullAttrs);
+ }
+ }else{ // complex collection
+ writer.startElement(
+ WCF_DATASERVICES_NAMESPACE,
+ XmlFormatParser.DATASERVICES_ELEMENT.getLocalPart());
+ // write complex property under
+ write(writer, object, nullAttrs);
+ writer.endElement(
+ WCF_DATASERVICES_NAMESPACE,
+ XmlFormatParser.DATASERVICES_ELEMENT.getLocalPart());
+ }
+ }
+ }
+ } catch (SecurityException e) {
+ getLogger().warning(
+ "Can't write the collection property: " + e.getMessage());
+ } catch (NoSuchFieldException e) {
+ getLogger().warning(
+ "Can't write the collection property: " + e.getMessage());
+ }
+ }
+ }
private void writeProperty(XmlWriter writer, Object entity,
Property prop, String getter,
@@ -1156,79 +1388,80 @@ private void writeProperty(XmlWriter writer, Object entity,
&& method.getParameterTypes().length == 0) {
Object value = null;
- try {
- value = method.invoke(entity,
- (Object[]) null);
- } catch (Exception e) {
- }
-
- if (value != null) {
- writer.startElement(
- WCF_DATASERVICES_NAMESPACE,
- prop.getName());
-
- if (prop instanceof ComplexProperty) {
- write(writer, value, nullAttrs);
- } else {
- writer.characters(TypeUtils.toEdm(
- value, prop.getType()));
- }
-
- writer.endElement(
- WCF_DATASERVICES_NAMESPACE,
- prop.getName());
- } else {
- if (prop.isNullable()) {
- writer.emptyElement(
- WCF_DATASERVICES_NAMESPACE,
- prop.getName(), prop.getName(),
- nullAttrs);
- } else {
- getLogger().warning(
- "The following property has a null value but is not marked as nullable: "
- + prop.getName());
- writer.emptyElement(
- WCF_DATASERVICES_NAMESPACE,
- prop.getName());
- }
- }
- break;
- }
+ try {
+ value = method.invoke(entity,
+ (Object[]) null);
+ } catch (Exception e) {
+ getLogger().warning(
+ "Error occurred while invoking the method : " + e.getMessage());
+ }
+
+ if (value != null) {
+ AttributesImpl typeAttr = new AttributesImpl();
+ if (prop instanceof ComplexProperty) { // if this is collection or complex type
+ if (value instanceof List) { // collection
+ writeCollectionProperty(writer,
+ entity, value, prop, nullAttrs);
+ } else { // complex type
+ EntityType type = ((Metadata) getMetadata()).getEntityType(entity.getClass());
+ // prefix the namespace for m:type
+ String packageName = type.getSchema().getNamespace().getName() + "." ;
+ typeAttr.addAttribute(
+ WCF_DATASERVICES_METADATA_NAMESPACE,
+ "type", "type", "string",packageName +
+ ((ComplexProperty) prop)
+ .getComplexType()
+ .getName());
+ writer.startElement(
+ WCF_DATASERVICES_NAMESPACE,
+ prop.getName(), prop.getName(),
+ typeAttr);
+ // write data
+ write(writer, value, nullAttrs);
+ }
+ } else {
+ typeAttr.addAttribute(
+ WCF_DATASERVICES_METADATA_NAMESPACE,
+ "type", "type", "string", prop
+ .getType().getName());
+ writer.startElement(
+ WCF_DATASERVICES_NAMESPACE,
+ prop.getName(), prop.getName(),
+ typeAttr);
+ writer.characters(TypeUtils.toEdm(
+ value, prop.getType()));
+ }
+
+ writer.endElement(
+ WCF_DATASERVICES_NAMESPACE,
+ prop.getName());
+ } else {
+ if (prop.isNullable()) {
+ writer.emptyElement(
+ WCF_DATASERVICES_NAMESPACE,
+ prop.getName(), prop.getName(),
+ nullAttrs);
+ } else {
+ getLogger().warning(
+ "The following property has a null value but is not marked as nullable: "
+ + prop.getName());
+ writer.emptyElement(
+ WCF_DATASERVICES_NAMESPACE,
+ prop.getName());
+ }
+ }
+ break;
+ }
}
}
};
r.setNamespaceAware(true);
+ result = new Entry();
+ Content content = new Content();
+ content.setInlineContent(r);
+ content.setToEncode(false);
- if (type.isBlob()) {
- result = new Entry() {
- @Override
- public void writeInlineContent(XmlWriter writer)
- throws SAXException {
- try {
- r.write(writer);
- } catch (IOException e) {
- throw new SAXException(e);
- }
- }
- };
- result.setNamespaceAware(true);
-
- Link editLink = new Link(getValueEditRef(entity),
- Relation.EDIT_MEDIA, null);
- result.getLinks().add(editLink);
- Content content = new Content();
- // Get the external blob reference
- content.setExternalRef(getValueRef(entity));
- content.setToEncode(false);
- result.setContent(content);
- } else {
- result = new Entry();
- Content content = new Content();
- content.setInlineContent(r);
- content.setToEncode(false);
-
- result.setContent(content);
- }
+ result.setContent(content);
}
}
@@ -1246,9 +1479,17 @@ public void updateEntity(Object entity) throws Exception {
if (getMetadata() == null || entity == null) {
return;
}
-
- Entry entry = toEntry(entity);
- ClientResource resource = createResource(getSubpath(entity));
+ EntityType type = metadata.getEntityType(entity.getClass());
+ ClientResource resource = createResource(getSubpath(entity));
+ if (type.isBlob()) {
+ InputStream inputStream = this.handleStreamingWithSlug(entity, type);
+ if (null != inputStream || isUpdateStreamData) {//Check for null inputstream and isUpdateStreamData=true then upadate null to stream data
+ resource.put(inputStream, slug, contentType);
+ }
+ // now do merge request for non-stream properties
+ this.mergeEntity(entity);
+ }else{
+ Entry entry = toEntry(entity);
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -1266,10 +1507,103 @@ public void updateEntity(Object entity) throws Exception {
} catch (ResourceException re) {
throw new ResourceException(re.getStatus(),
"Can't update this entity " + resource.getReference());
+ } finally {
+ this.latestRequest = resource.getRequest();
+ this.latestResponse = resource.getResponse();
+ }
+ }
+ }
+
+ /**
+ * Method for merger operation.
+ * @param entity
+ * The entity to merge.
+ */
+ public void mergeEntity(Object entity) {
+ this.merge(entity,null);
+ }
+
+ /**
+ * Updates an entity.
+ *
+ * @param entity
+ * The entity to put.
+ * @throws Exception
+ */
+ private void merge(Object entity,String id) {
+ if (getMetadata() == null || entity == null) {
+ return;
+ }
+ EntityType type = metadata.getEntityType(entity.getClass());
+ if (type.isBlob()) {
+ List properties = type.getProperties();
+ Iterator iterator = properties.iterator();
+ while (iterator.hasNext()) {
+ Property prop = iterator.next();
+ if (prop.getType().getName().contains("Stream")) {
+ try {
+ // merge request should not contain data for stream property, so setting it to null.
+ ReflectUtils.invokeSetter(entity, prop.getNormalizedName(), null);
+ } catch (Exception e) {
+ getLogger().warning(
+ "Can't merge the object: " + e.getMessage());
+ }
+ break;
+ }
+
+ }
+ }
+ Entry entry = toEntry(entity);
+
+ ClientResource resource;
+ if(null!=id){
+ resource = createResource(new Reference(id));
+ }
+ else{
+ resource= createResource(getSubpath(entity));
+ }
+
+
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ entry.write(baos);
+ baos.flush();
+ StringRepresentation r = new StringRepresentation(baos.toString(), MediaType.APPLICATION_ATOM);
+ String tag = getTag(entity);
+
+ if (tag != null) {
+ // Add a condition
+ resource.getConditions().setMatch(Arrays.asList(new Tag(tag)));
+ }
+ resource.merge(r);
+ } catch (ResourceException re) {
+ throw new ResourceException(re.getStatus(),
+ "Can't update this entity " + resource.getReference());
+ } catch (IOException io) {
+ getLogger().warning(
+ "IO exception while merging the entity: " + io.getMessage());
} finally {
this.latestRequest = resource.getRequest();
this.latestResponse = resource.getResponse();
}
}
+ /**
+ * Gets Query parameter.
+ *
+ * @return the parameter
+ */
+ public Map getParameter() {
+ return parameters;
+ }
+
+ /**
+ * Sets Query parameter in request header.
+ *
+ * @param parameter the parameter
+ */
+ public void setParameters(Map parameters) {
+ this.parameters = parameters;
+ }
+
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/BatchProperty.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/BatchProperty.java
new file mode 100644
index 0000000000..f32b3c677a
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/BatchProperty.java
@@ -0,0 +1,52 @@
+package org.restlet.ext.odata.batch.request;
+
+import org.restlet.data.Method;
+import org.restlet.ext.odata.Service;
+import org.restlet.ext.odata.internal.edm.EntityType;
+
+/**
+ * The Interface BatchProperty handles the properties of a CRUD requests.
+ *
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public interface BatchProperty extends ClientBatchRequest {
+
+ /**
+ * Gets the entity class.
+ *
+ * @return the entityClass
+ */
+ public Class> getEntityClass();
+
+ /**
+ * Gets the service.
+ *
+ * @return the service
+ */
+ public Service getService();
+
+ /**
+ * Gets the entity type.
+ *
+ * @return the entity type
+ */
+ public EntityType getEntityType();
+
+ /**
+ * Gets the method.
+ *
+ * @return the method
+ */
+ public Method getMethod();
+
+ /**
+ * Gets the entity set name.
+ *
+ * @return the entity set name
+ */
+ public String getEntitySetName();
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/BatchRequest.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/BatchRequest.java
new file mode 100644
index 0000000000..052257c05a
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/BatchRequest.java
@@ -0,0 +1,44 @@
+package org.restlet.ext.odata.batch.request;
+
+import java.util.List;
+
+import org.restlet.ext.odata.batch.request.impl.GetEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+
+/**
+ * The Interface BatchRequest is the base interface for batch.
+ * It has methods to add requests like changeset requests and CRUD requets.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ *
+ */
+public interface BatchRequest {
+
+ /**
+ * Used for Reading the entities.
+ *
+ * @param getEntityRequest
+ * the get entity request
+ * @return the batch request impl
+ */
+ public BatchRequest addRequest(GetEntityRequest getEntityRequest);
+
+ /**
+ * Used for adding changeSetRequest.
+ *
+ * @param changeSetRequest
+ * the change set request
+ * @return the batch request impl
+ */
+ public BatchRequest addRequest(ChangeSetRequest changeSetRequest);
+
+ /**
+ * To execute the batch request.
+ *
+ * @return the list of batch response
+ */
+ public List execute();
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/ChangeSetRequest.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/ChangeSetRequest.java
new file mode 100644
index 0000000000..3bbfd63696
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/ChangeSetRequest.java
@@ -0,0 +1,53 @@
+package org.restlet.ext.odata.batch.request;
+
+import java.util.List;
+
+import org.restlet.ext.odata.batch.request.impl.CreateEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.DeleteEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.UpdateEntityRequest;
+
+/**
+ * The Interface ChangeSetRequest defines the methods of batch changeset
+ * requests.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public interface ChangeSetRequest extends ClientBatchRequest {
+
+ /**
+ * Gets the list of requests.
+ *
+ * @return the reqs
+ */
+ public List getReqs();
+
+ /**
+ * Adds the request.
+ *
+ * @param createEntityRequest
+ * the create entity request
+ * @return the change set request
+ */
+ public ChangeSetRequest addRequest(CreateEntityRequest createEntityRequest);
+
+ /**
+ * Adds the request.
+ *
+ * @param updateEntityRequest
+ * the update entity request
+ * @return the change set request
+ */
+ public ChangeSetRequest addRequest(UpdateEntityRequest updateEntityRequest);
+
+ /**
+ * Adds the request.
+ *
+ * @param deleteEntityRequest
+ * the delete entity request
+ * @return the change set request
+ */
+ public ChangeSetRequest addRequest(DeleteEntityRequest deleteEntityRequest);
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/ClientBatchRequest.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/ClientBatchRequest.java
new file mode 100644
index 0000000000..22c3a4c501
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/ClientBatchRequest.java
@@ -0,0 +1,25 @@
+package org.restlet.ext.odata.batch.request;
+
+import org.restlet.data.MediaType;
+
+/**
+ * The Interface ClientBatchRequest forms the base interface for all types of
+ * requests like CRUD and changeset requests.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ *
+ */
+public interface ClientBatchRequest {
+
+ /**
+ * Format.
+ *
+ * @param formatType
+ * the format type
+ * @return the string
+ */
+ public String format(MediaType formatType);
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/BatchRequestImpl.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/BatchRequestImpl.java
new file mode 100644
index 0000000000..a2f3f3f6ad
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/BatchRequestImpl.java
@@ -0,0 +1,219 @@
+package org.restlet.ext.odata.batch.request.impl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.restlet.Client;
+import org.restlet.Context;
+import org.restlet.data.ClientInfo;
+import org.restlet.data.MediaType;
+import org.restlet.data.Method;
+import org.restlet.data.Protocol;
+import org.restlet.data.Reference;
+import org.restlet.ext.odata.Service;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.ChangeSetRequest;
+import org.restlet.ext.odata.batch.request.ClientBatchRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.util.BatchConstants;
+import org.restlet.ext.odata.batch.util.BodyPart;
+import org.restlet.ext.odata.batch.util.Multipart;
+import org.restlet.ext.odata.batch.util.RestletBatchRequestHelper;
+import org.restlet.representation.Representation;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.ClientResource;
+
+/**
+ * The Class BatchRequestImpl forms the base class for batch request.
+ * It maintains the list of clientBatchRequests within a batch.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class BatchRequestImpl implements BatchRequest {
+
+ /** The service. */
+ private Service service;
+
+ /** The requests. */
+ private List requests = new ArrayList();
+
+ /**
+ * Instantiates a new batch request impl.
+ *
+ * @param service
+ * the service
+ */
+ public BatchRequestImpl(Service service) {
+ this.service = service;
+ }
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.BatchRequest#addRequest(org.restlet.ext.odata.batch.request.impl.GetEntityRequest)
+ */
+ @Override
+ public BatchRequest addRequest(GetEntityRequest getEntityRequest) {
+ requests.add(getEntityRequest);
+ return this;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.BatchRequest#addRequest(org.restlet.ext.odata.batch.request.ChangeSetRequest)
+ */
+ @Override
+ public BatchRequest addRequest(ChangeSetRequest changeSetRequest) {
+ requests.add(changeSetRequest);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.BatchRequest#execute()
+ */
+ @Override
+ public List execute() {
+
+ String batchId = generateBatchId();
+
+ ClientResource clientResource = service.createResource(new Reference(
+ service.getServiceRef()));
+ Reference resourceRef = clientResource.getRequest().getResourceRef();
+
+ // create the client Info
+ setClientContext(clientResource, resourceRef);
+
+ StringBuilder sb = createBatchString(batchId, this.requests);
+ //Finally posting the batch request.
+ Representation r = clientResource.post(new StringRepresentation(sb
+ .toString(), new MediaType(MediaType.MULTIPART_MIXED
+ + ";boundary=" + batchId)));
+
+ List batchResponses = null;
+ try {
+ batchResponses = parseRepresentation(r, this.requests);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return batchResponses;
+ }
+
+ /**
+ * Creates the batch request string,which would then be converted into String Representation for further processing.
+ *
+ * @param batchId
+ * @param list
+ * @return
+ */
+ private StringBuilder createBatchString(String batchId,
+ List list) {
+ StringBuilder sb = new StringBuilder();
+
+
+ for (ClientBatchRequest restletBatchRequest : list) {
+ if (restletBatchRequest instanceof GetEntityRequest) {
+ sb.append(BatchConstants.NEW_LINE_BATCH_START).append(batchId).append(BatchConstants.NEW_LINE);
+ sb.append(restletBatchRequest.format(MediaType.APPLICATION_ATOM));
+ } else if (restletBatchRequest instanceof ChangeSetRequest) {
+ sb.append(BatchConstants.NEW_LINE_BATCH_START).append(batchId).append(BatchConstants.NEW_LINE);
+ sb.append(restletBatchRequest.format(MediaType.APPLICATION_ATOM));
+ }
+ }
+ sb.append(BatchConstants.NEW_LINE_BATCH_START).append(batchId).append(BatchConstants.NEW_LINE_BATCH_END);
+ return sb;
+ }
+
+ /**
+ * Sets the client information and the context onto client resource.
+ * @param clientResource
+ * @param resourceRef
+ */
+ private void setClientContext(ClientResource clientResource,
+ Reference resourceRef) {
+ ClientInfo clientInfo = new ClientInfo();
+ clientResource.getRequest().setClientInfo(clientInfo);
+
+ Context context = new Context();
+ Client client = new Client(context, Protocol.HTTP);
+ client.getContext().getParameters()
+ .add("useForwardedForHeader", "false");
+
+
+ clientResource.getRequest().setResourceRef(
+ new Reference(resourceRef.getTargetRef()
+ + BatchConstants.BATCH_ENDPOINT_URI));
+ clientResource.getRequest().setMethod(Method.POST);
+ clientResource.setNext(client);
+ }
+
+ /**
+ * Generates a unique batch Id for each batch request.
+ * @return
+ */
+ private String generateBatchId() {
+ String batchId = BatchConstants.BATCH_UNDERSCORE
+ + UUID.randomUUID().toString();
+ return batchId;
+ }
+
+ /**
+ * This method parses the representation and returns the list of batch
+ * responses.
+ *
+ * @param r
+ * representation
+ * @param list
+ * the list
+ * @return list of batchResponses.
+ * @throws IOException
+ */
+ private List parseRepresentation(Representation r,
+ List list) throws IOException {
+
+ // This would hold individual batch responses
+ List batchResultList = new ArrayList(
+ list.size());
+
+ MediaType mediaType = r.getMediaType();
+ Multipart baseMultiPart = RestletBatchRequestHelper.createMultipart(
+ r.getStream(), mediaType);
+ int i = 0;
+ BatchResponse bResponse = null;
+ List subBodyParts = baseMultiPart.getBodyParts();
+ for (BodyPart bp : subBodyParts) {
+ // Its a changeset
+ if (bp.getMediaType().isCompatible(MediaType.MULTIPART_MIXED)) {
+ Multipart mp = RestletBatchRequestHelper.createMultipart(
+ bp.getInputStream(), bp.getMediaType());
+ List contentList = new ArrayList();
+ List bodyParts = mp.getBodyParts();
+ for (BodyPart bodyPart : bodyParts) {
+ contentList
+ .add(RestletBatchRequestHelper
+ .getStringFromInputStream(bodyPart
+ .getInputStream()));
+ }
+ ChangeSetRequest csr = (ChangeSetRequest) list.get(i);
+ bResponse = RestletBatchRequestHelper.parseChangeSetResponse(
+ BatchConstants.ODATA_VERSION_V3, contentList, csr,
+ mediaType, service);
+ } else {
+ ClientBatchRequest batchRequestOfTypeGet = list.get(i);
+ String content = RestletBatchRequestHelper
+ .getStringFromInputStream(bp.getInputStream());
+ bResponse = RestletBatchRequestHelper
+ .parseSingleOperationResponse(
+ BatchConstants.ODATA_VERSION_V3, content,
+ batchRequestOfTypeGet, bp.getMediaType(),
+ service);
+ }
+ batchResultList.add(bResponse);
+ i++;
+ }
+ return batchResultList;
+
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/ChangeSetRequestImpl.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/ChangeSetRequestImpl.java
new file mode 100644
index 0000000000..c855171058
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/ChangeSetRequestImpl.java
@@ -0,0 +1,100 @@
+package org.restlet.ext.odata.batch.request.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.restlet.data.MediaType;
+import org.restlet.engine.header.HeaderConstants;
+import org.restlet.ext.odata.batch.request.ChangeSetRequest;
+import org.restlet.ext.odata.batch.request.ClientBatchRequest;
+import org.restlet.ext.odata.batch.util.BatchConstants;
+
+
+/**
+ * The Class ChangeSetRequestImpl.
+ *
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class ChangeSetRequestImpl implements ChangeSetRequest {
+
+ /** The reqs. */
+ private List reqs = new ArrayList();
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.ChangeSetRequest#addRequest(org.restlet.ext.odata.batch.request.impl.CreateEntityRequest)
+ */
+ @Override
+ public ChangeSetRequest addRequest(CreateEntityRequest createEntityRequest) {
+ reqs.add(createEntityRequest);
+ return this;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.ChangeSetRequest#getReqs()
+ */
+ @Override
+ public List getReqs() {
+ return reqs;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.ClientBatchRequest#format(org.restlet.data.MediaType)
+ */
+ @Override
+ public String format(MediaType formatType) {
+
+ StringBuilder sb = new StringBuilder();
+ // nothing to add
+ if (reqs == null || reqs.size() == 0) {
+ return "";
+ }
+
+ String boundary = BatchConstants.CHANGESET_UNDERSCORE
+ + UUID.randomUUID().toString();
+ String cType = MediaType.MULTIPART_MIXED + "; "
+ + BatchConstants.BATCH_BOUNDARY + "=" + boundary;
+ sb.append(HeaderConstants.HEADER_CONTENT_TYPE).append(": ")
+ .append(cType).append(BatchConstants.NEW_LINE);
+ sb.append(BatchConstants.NEW_LINE);
+
+
+ for (ClientBatchRequest req : reqs) {
+ sb.append(BatchConstants.NEW_LINE_BATCH_START).append(boundary).append(BatchConstants.NEW_LINE);
+ sb.append(req.format(formatType));
+ }
+
+ // ending the change set
+ sb.append(BatchConstants.NEW_LINE_BATCH_START).append(boundary).append(BatchConstants.NEW_LINE_BATCH_END);
+
+ return sb.toString();
+
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.ChangeSetRequest#addRequest(org.restlet.ext.odata.batch.request.impl.UpdateEntityRequest)
+ */
+ @Override
+ public ChangeSetRequest addRequest(UpdateEntityRequest updateEntityRequest) {
+ reqs.add(updateEntityRequest);
+ return this;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.ChangeSetRequest#addRequest(org.restlet.ext.odata.batch.request.impl.DeleteEntityRequest)
+ */
+ @Override
+ public ChangeSetRequest addRequest(DeleteEntityRequest deleteEntityRequest) {
+ reqs.add(deleteEntityRequest);
+ return this;
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/CreateEntityRequest.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/CreateEntityRequest.java
new file mode 100644
index 0000000000..a8a7ddb1a4
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/CreateEntityRequest.java
@@ -0,0 +1,80 @@
+package org.restlet.ext.odata.batch.request.impl;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Method;
+import org.restlet.engine.header.HeaderConstants;
+import org.restlet.ext.atom.Entry;
+import org.restlet.ext.odata.Service;
+import org.restlet.ext.odata.batch.util.BatchConstants;
+import org.restlet.ext.odata.batch.util.RestletBatchRequestHelper;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.ClientResource;
+
+/**
+ * The Class CreateEntityRequest is used with POST method to create an entity
+ * using batch.
+ *
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class CreateEntityRequest extends RestletBatchRequest {
+
+ /** The entry. */
+ private Entry entry;
+
+ /**
+ * Instantiates a new creates the entity request.
+ *
+ * @param service
+ * the service
+ * @param entity
+ * the entity
+ * @throws Exception
+ * the exception
+ */
+ public CreateEntityRequest(Service service, Object entity) throws Exception {
+ super(service, (Class>) entity.getClass(), Method.POST);
+ this.entry = service.toEntry(entity);
+ }
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.ClientBatchRequest#format(org.restlet.data.MediaType)
+ */
+ @Override
+ public String format(MediaType formatType) {
+ ClientResource cr = getClientResource(this.getEntitySetName());
+ StringRepresentation strRepresent = RestletBatchRequestHelper
+ .getStringRepresentation(this.getService(),
+ this.getEntitySetName(), this.entry,formatType);
+ StringBuilder sb = new StringBuilder();
+ sb.append(RestletBatchRequestHelper.formatSingleRequest(
+ cr.getRequest(), formatType));
+ // set content-length
+ sb.append(HeaderConstants.HEADER_CONTENT_LENGTH).append(": ")
+ .append(strRepresent.getSize()).append(BatchConstants.NEW_LINE);
+ sb.append(BatchConstants.NEW_LINE).append(BatchConstants.NEW_LINE);
+ sb.append(strRepresent.getText()).append(BatchConstants.NEW_LINE);
+ return sb.toString();
+ }
+
+ /**
+ * Gets the entry.
+ *
+ * @return the entry
+ */
+ public Entry getEntry() {
+ return entry;
+ }
+
+ /**
+ * Sets the entry.
+ *
+ * @param entry
+ * the new entry
+ */
+ public void setEntry(Entry entry) {
+ this.entry = entry;
+ }
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/DeleteEntityRequest.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/DeleteEntityRequest.java
new file mode 100644
index 0000000000..3bee4c759a
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/DeleteEntityRequest.java
@@ -0,0 +1,73 @@
+package org.restlet.ext.odata.batch.request.impl;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Method;
+import org.restlet.ext.atom.Entry;
+import org.restlet.ext.odata.Service;
+import org.restlet.ext.odata.batch.util.RestletBatchRequestHelper;
+import org.restlet.resource.ClientResource;
+
+/**
+ * The Class DeleteEntityRequest is used with DELETE method to delete an entity
+ * using batch..
+ *
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class DeleteEntityRequest extends RestletBatchRequest {
+
+ /** The entry. */
+ private Entry entry;
+
+ /** The entity sub path. */
+ private String entitySubPath;
+
+ /**
+ * Instantiates a new delete entity request.
+ *
+ * @param service
+ * the service
+ * @param entity
+ * the entity
+ * @throws Exception
+ * the exception
+ */
+ public DeleteEntityRequest(Service service, Object entity) throws Exception {
+ super(service, entity.getClass(), Method.DELETE);
+ this.entry = service.toEntry(entity);
+ this.entitySubPath = RestletBatchRequestHelper.getEntitySubPath(
+ service, entity);
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.ClientBatchRequest#format(org.restlet.data.MediaType)
+ */
+ @Override
+ public String format(MediaType formatType) {
+ ClientResource cr = getClientResource(this.entitySubPath);
+ return RestletBatchRequestHelper.formatSingleRequest(cr.getRequest(),
+ formatType);
+ }
+
+ /**
+ * Gets the entry.
+ *
+ * @return the entry
+ */
+ public Entry getEntry() {
+ return entry;
+ }
+
+ /**
+ * Sets the entry.
+ *
+ * @param entry
+ * the new entry
+ */
+ public void setEntry(Entry entry) {
+ this.entry = entry;
+ }
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/GetEntityRequest.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/GetEntityRequest.java
new file mode 100644
index 0000000000..a7ffa37a7d
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/GetEntityRequest.java
@@ -0,0 +1,58 @@
+package org.restlet.ext.odata.batch.request.impl;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Method;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.util.RestletBatchRequestHelper;
+import org.restlet.resource.ClientResource;
+
+/**
+ * The Class GetEntityRequest is specifically used within a batch request,to
+ * fetch the entity.
+ *
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class GetEntityRequest extends RestletBatchRequest {
+
+ /** The query. */
+ private Query> query;
+
+ /**
+ * Instantiates a new gets the entity request.
+ *
+ * @param service
+ * the service
+ * @param query
+ * the query
+ * @throws Exception
+ */
+ public GetEntityRequest(Query> query) throws Exception {
+ super(query.getService(), query.getEntityClass(), Method.GET);
+ this.query = query;
+ }
+
+ /**
+ * Gets the query.
+ *
+ * @return the query
+ */
+ public Query> getQuery() {
+ return query;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.ClientBatchRequest#format(org.restlet.data.MediaType)
+ */
+ @Override
+ public String format(MediaType formatType) {
+ ClientResource cr = getClientResource(this.query.getSubpath());
+ return RestletBatchRequestHelper.formatSingleRequest(cr.getRequest(),
+ formatType);
+ }
+
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/RestletBatchRequest.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/RestletBatchRequest.java
new file mode 100644
index 0000000000..32e20d1411
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/RestletBatchRequest.java
@@ -0,0 +1,165 @@
+package org.restlet.ext.odata.batch.request.impl;
+
+import org.restlet.data.Method;
+import org.restlet.ext.odata.Service;
+import org.restlet.ext.odata.batch.request.BatchProperty;
+import org.restlet.ext.odata.batch.util.RestletBatchRequestHelper;
+import org.restlet.ext.odata.internal.edm.EntityType;
+import org.restlet.ext.odata.internal.edm.Metadata;
+import org.restlet.resource.ClientResource;
+
+
+/**
+ * Abstract implementation of the RestletBatchRequest interface to handle the
+ * mechanism for inferring the entity type from the entity class using the
+ * service, for CRUD requests.
+ *
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public abstract class RestletBatchRequest implements BatchProperty {
+
+ /** The service. */
+ private Service service;
+
+ /** The entity class. */
+ private Class> entityClass;
+
+ /** The entity type. */
+ private EntityType entityType;
+
+ /** The method. */
+ private Method method;
+
+ /** The entity set name. */
+ private String entitySetName;
+
+ /**
+ * Instantiates a new restlet batch request impl.
+ *
+ * @param service the service
+ * @param entityClass the entity class
+ * @param method the method
+ * @throws Exception the exception
+ */
+ public RestletBatchRequest(Service service, Class> entityClass,
+ Method method) throws Exception {
+ this.setService(service);
+ this.setEntityClass(entityClass);
+ this.entityType = inferEntityType(entityClass);
+ this.method = method;
+ this.setEntitySetName(RestletBatchRequestHelper
+ .validateAndReturnEntitySetName(service, entityClass));
+ }
+
+ /**
+ * Method to get the entity type from the entity class.
+ *
+ * @param entityClass
+ * the entity class
+ * @return the entity type
+ */
+ private EntityType inferEntityType(Class> entityClass) {
+ Metadata metadata = (Metadata) service.getMetadata();
+ return metadata.getEntityType(entityClass);
+ }
+
+ /**
+ * Gets the client resource.
+ *
+ * @param relativePath the relative path
+ * @return the client resource
+ */
+ public ClientResource getClientResource(String relativePath) {
+ ClientResource cr = this.getService().createResource(relativePath);
+ cr.getRequest().setMethod(this.getMethod());
+ return cr;
+ }
+
+ /**
+ * Gets the entity class.
+ *
+ * @return the entityClass
+ */
+ public Class> getEntityClass() {
+ return entityClass;
+ }
+
+ /**
+ * Sets the entity class.
+ *
+ * @param entityClass
+ * the entityClass to set
+ */
+ public void setEntityClass(Class> entityClass) {
+ this.entityClass = entityClass;
+ }
+
+ /**
+ * Gets the service.
+ *
+ * @return the service
+ */
+ public Service getService() {
+ return service;
+ }
+
+ /**
+ * Sets the service.
+ *
+ * @param service
+ * the service to set
+ */
+ public void setService(Service service) {
+ this.service = service;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.BatchProperty#getEntityType()
+ */
+ @Override
+ public EntityType getEntityType() {
+ return entityType;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.BatchProperty#getMethod()
+ */
+ @Override
+ public Method getMethod() {
+ return method;
+ }
+
+ /**
+ * Sets the method.
+ *
+ * @param method
+ * the new method
+ */
+ protected void setMethod(Method method) {
+ this.method = method;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.BatchProperty#getEntitySetName()
+ */
+ @Override
+ public String getEntitySetName() {
+ return entitySetName;
+ }
+
+ /**
+ * Sets the entity set name.
+ *
+ * @param entitySetName
+ * the new entity set name
+ */
+ public void setEntitySetName(String entitySetName) {
+ this.entitySetName = entitySetName;
+ }
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/UpdateEntityRequest.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/UpdateEntityRequest.java
new file mode 100644
index 0000000000..507641896e
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/request/impl/UpdateEntityRequest.java
@@ -0,0 +1,86 @@
+package org.restlet.ext.odata.batch.request.impl;
+
+import org.restlet.data.MediaType;
+import org.restlet.data.Method;
+import org.restlet.engine.header.HeaderConstants;
+import org.restlet.ext.atom.Entry;
+import org.restlet.ext.odata.Service;
+import org.restlet.ext.odata.batch.util.BatchConstants;
+import org.restlet.ext.odata.batch.util.RestletBatchRequestHelper;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.ClientResource;
+
+/**
+ * The Class UpdateEntityRequest is used with PUT method to update an entity
+ * using batch.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class UpdateEntityRequest extends RestletBatchRequest {
+
+ /** The entry. */
+ private Entry entry;
+
+ /** The entity sub path. */
+ private String entitySubPath;
+
+ /**
+ * Instantiates a new update entity request.
+ *
+ * @param service
+ * the service
+ * @param entity
+ * the entity
+ * @throws Exception
+ * the exception
+ */
+ public UpdateEntityRequest(Service service, Object entity) throws Exception {
+ super(service, entity.getClass(), Method.PUT);
+
+ this.entry = service.toEntry(entity);
+ this.entitySubPath = RestletBatchRequestHelper.getEntitySubPath(
+ service, entity);
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.request.ClientBatchRequest#format(org.restlet.data.MediaType)
+ */
+ @Override
+ public String format(MediaType formatType) {
+ ClientResource cr = getClientResource(this.entitySubPath);
+ StringRepresentation strRepresent = RestletBatchRequestHelper
+ .getStringRepresentation(this.getService(),
+ this.getEntitySetName(), this.entry,formatType);
+ StringBuilder sb = new StringBuilder();
+ sb.append(RestletBatchRequestHelper.formatSingleRequest(
+ cr.getRequest(), formatType));
+ // set content-length
+ sb.append(HeaderConstants.HEADER_CONTENT_LENGTH).append(": ")
+ .append(strRepresent.getSize()).append(BatchConstants.NEW_LINE);
+ sb.append(BatchConstants.NEW_LINE).append(BatchConstants.NEW_LINE);
+ sb.append(strRepresent.getText()).append(BatchConstants.NEW_LINE);
+ return sb.toString();
+ }
+
+ /**
+ * Gets the entry.
+ *
+ * @return the entry
+ */
+ public Entry getEntry() {
+ return entry;
+ }
+
+ /**
+ * Sets the entry.
+ *
+ * @param entry
+ * the new entry
+ */
+ public void setEntry(Entry entry) {
+ this.entry = entry;
+ }
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/BatchResponse.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/BatchResponse.java
new file mode 100644
index 0000000000..d54487ea53
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/BatchResponse.java
@@ -0,0 +1,35 @@
+package org.restlet.ext.odata.batch.response;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+/**
+ * The Interface BatchResponse is the top level response interface for a batch.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public interface BatchResponse {
+
+ /**
+ * Gets the entity.
+ *
+ * @return the entity
+ */
+ Object getEntity();
+
+ /**
+ * Gets the status.
+ *
+ * @return the status
+ */
+ int getStatus();
+
+ /**
+ * Gets the headers.
+ *
+ * @return the headers
+ */
+ MultivaluedMap getHeaders();
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/ChangeSetResponse.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/ChangeSetResponse.java
new file mode 100644
index 0000000000..9970fa67d3
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/ChangeSetResponse.java
@@ -0,0 +1,22 @@
+package org.restlet.ext.odata.batch.response;
+
+/**
+ * The Interface ChangeSetResponse exposes methods to hold the CUD responses
+ * within a batch response.
+ *
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public interface ChangeSetResponse extends BatchResponse {
+
+ /**
+ * Adds the.
+ *
+ * @param singleResponse
+ * the single response
+ */
+ void add(BatchResponse singleResponse);
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/impl/BatchResponseImpl.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/impl/BatchResponseImpl.java
new file mode 100644
index 0000000000..73b857fafe
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/impl/BatchResponseImpl.java
@@ -0,0 +1,72 @@
+package org.restlet.ext.odata.batch.response.impl;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.restlet.ext.odata.batch.response.BatchResponse;
+
+/**
+ * The Class BatchResponseImpl is the implementation class for hold the state of
+ * the response.
+ * It contains properties like status returned by the http
+ * response,headers,object entity in case of Create and Get entity requests.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class BatchResponseImpl implements BatchResponse {
+
+ /** The status. */
+ private int status;
+
+ /** The headers. */
+ final MultivaluedMap headers;
+
+ /** The entity. */
+ private Object entity;
+
+ /**
+ * Instantiates a new batch response impl.
+ *
+ * @param statusCode
+ * the status code
+ * @param batchHeaders
+ * the batch headers
+ * @param entity
+ * the entity
+ */
+ public BatchResponseImpl(int statusCode,
+ MultivaluedMap batchHeaders, Object entity) {
+ this.entity = entity;
+ this.status = statusCode;
+ this.headers = batchHeaders;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.response.BatchResponse#getEntity()
+ */
+ @Override
+ public Object getEntity() {
+ return entity;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.response.BatchResponse#getStatus()
+ */
+ @Override
+ public int getStatus() {
+ return status;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.response.BatchResponse#getHeaders()
+ */
+ @Override
+ public MultivaluedMap getHeaders() {
+ return headers;
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/impl/ChangeSetResponseImpl.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/impl/ChangeSetResponseImpl.java
new file mode 100644
index 0000000000..0bb2ff33ed
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/response/impl/ChangeSetResponseImpl.java
@@ -0,0 +1,66 @@
+package org.restlet.ext.odata.batch.response.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.ext.odata.batch.util.BatchConstants;
+
+/**
+ * The Class ChangeSetResponseImpl is implementation class for Changeset
+ * response.
+ * The changeset response can have a list of multiple responses within,based on
+ * the requests sent in a chnageset of a batch.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class ChangeSetResponseImpl implements ChangeSetResponse {
+
+ /** The responses. */
+ List responses = new ArrayList();
+
+ /** The status. */
+ int status = BatchConstants.HTTP_STATUS_OK;
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.response.BatchResponse#getEntity()
+ */
+ @Override
+ public Object getEntity() {
+ return responses;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.response.BatchResponse#getStatus()
+ */
+ @Override
+ public int getStatus() {
+ return status;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.response.BatchResponse#getHeaders()
+ */
+ @Override
+ public MultivaluedMap getHeaders() {
+ return null;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.batch.response.ChangeSetResponse#add(org.restlet.ext.odata.batch.response.BatchResponse)
+ */
+ @Override
+ public void add(BatchResponse singleResponse) {
+ responses.add(singleResponse);
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/BatchConstants.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/BatchConstants.java
new file mode 100644
index 0000000000..03f1aac662
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/BatchConstants.java
@@ -0,0 +1,38 @@
+package org.restlet.ext.odata.batch.util;
+
+/**
+ * Interface to hold constants for Restlet batch implementation.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ *
+ */
+public interface BatchConstants {
+
+ /** The Constant BATCH_ENDPOINT_URI. */
+ String BATCH_ENDPOINT_URI = "$batch";
+
+ String ODATA_VERSION_V3 = "V3";
+
+ String HTTP_HEADER_CONTENT_TYPE = "Content-Type";
+
+ String GET_METADATA = "getMetadata";
+
+ String BATCH_BOUNDARY = "boundary";
+
+ /** The Constant STATUS. */
+ int HTTP_STATUS_OK = 200;
+
+ String CHANGESET_UNDERSCORE = "changeset_";
+
+ String BATCH_UNDERSCORE = "batch_";
+
+ String NEW_LINE = System.getProperty("line.separator");
+
+ String NEW_LINE_BATCH_START = new StringBuilder().append(NEW_LINE).append("--").toString();
+
+ String NEW_LINE_BATCH_END = new StringBuilder().append("--").append(NEW_LINE).toString();
+
+ String FORMAT_TYPE_CHARSET_UTF8 = ";charset=utf-8";
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/BodyPart.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/BodyPart.java
new file mode 100644
index 0000000000..f469503457
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/BodyPart.java
@@ -0,0 +1,179 @@
+package org.restlet.ext.odata.batch.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.jvnet.mimepull.MIMEPart;
+import org.restlet.data.MediaType;
+
+/**
+ * The Class BodyPart is sub part of the Multipart.
+ * Body part represents a single attachment from the Mime message attachments.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class BodyPart implements Closeable {
+
+ /** The mime part. */
+ private MIMEPart mimePart;
+
+ /** The media type. */
+ private MediaType mediaType;
+
+ /** The entity. */
+ private Object entity;
+
+ /** The headers. */
+ private MultivaluedMap headers = new HeaderMap();
+
+ /** The content disposition. */
+ private String contentDisposition;
+
+ /** The parent. */
+ private Multipart parent;
+
+ /**
+ * Instantiates a new body part.
+ *
+ * @param mimePart
+ * the mime part
+ */
+ public BodyPart(MIMEPart mimePart) {
+ this.mimePart = mimePart;
+ }
+
+ /**
+ * Instantiates a new body part.
+ */
+ public BodyPart() {
+
+ }
+
+ /**
+ * Gets the entity.
+ *
+ * @return the entity
+ */
+ public Object getEntity() {
+ return entity;
+ }
+
+ /**
+ * Sets the entity.
+ *
+ * @param entity
+ * the new entity
+ */
+ public void setEntity(Object entity) {
+ this.entity = entity;
+ }
+
+ /**
+ * Gets the headers.
+ *
+ * @return the headers
+ */
+ public MultivaluedMap getHeaders() {
+ return headers;
+ }
+
+ /**
+ * Sets the headers.
+ *
+ * @param headers
+ * the headers
+ */
+ public void setHeaders(MultivaluedMap headers) {
+ this.headers = headers;
+ }
+
+ /**
+ * Gets the content disposition.
+ *
+ * @return the content disposition
+ */
+ public String getContentDisposition() {
+ return contentDisposition;
+ }
+
+ /**
+ * Sets the content disposition.
+ *
+ * @param contentDisposition
+ * the new content disposition
+ */
+ public void setContentDisposition(String contentDisposition) {
+ this.contentDisposition = contentDisposition;
+ }
+
+ /**
+ * Gets the media type.
+ *
+ * @return the media type
+ */
+ public MediaType getMediaType() {
+ return mediaType;
+ }
+
+ /**
+ * Sets the media type.
+ *
+ * @param mediaType
+ * the new media type
+ */
+ public void setMediaType(MediaType mediaType) {
+ this.mediaType = mediaType;
+ }
+
+ /**
+ * Sets the parent and add the current bodyPart as child.
+ *
+ * @param multipart
+ * the new parent
+ */
+ public void setParent(Multipart multipart) {
+ this.parent = multipart;
+ }
+
+ /**
+ * Gets the parent.
+ *
+ * @return the parent
+ */
+ public Multipart getParent() {
+ return parent;
+ }
+
+ /**
+ * Gets the input stream.
+ *
+ * @return the input stream
+ */
+ public InputStream getInputStream() {
+ return this.mimePart.read();
+ }
+
+ /**
+ * Clean up temporary file(s), if any were utilized.
+ */
+ public void cleanup() {
+ mimePart.close();
+ }
+
+ // Closeable
+ /**
+ * Defer to {@link #cleanup}.
+ *
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public void close() throws IOException {
+ cleanup();
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/HeaderMap.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/HeaderMap.java
new file mode 100644
index 0000000000..23fe8aedb2
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/HeaderMap.java
@@ -0,0 +1,84 @@
+package org.restlet.ext.odata.batch.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+/**
+ * A {@link MultivaluedMap} with String keys and values backed by a HashMap.
+ *
+ * Although keys are stored case-sensitive, all (internal) comparisons are done
+ * case-insensitive. I.e. {@code get("key")} and {@code get("KEY")} return the
+ * same values.
+ */
+public class HeaderMap extends HashMap> implements
+ MultivaluedMap {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -913599179728662269L;
+
+ @Override
+ public void putSingle(String key, String value) {
+ List values = new ArrayList();
+ values.add(value);
+ this.put(key, values);
+ }
+
+ @Override
+ public void add(String key, String value) {
+ List values = this.get(key);
+ if (values == null)
+ values = new ArrayList();
+ values.add(value);
+ this.put(key, values);
+ }
+
+ @Override
+ public String getFirst(String key) {
+ List values = this.get(key);
+ if (values == null || values.size() == 0)
+ return null;
+ return values.get(0);
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ for (String k : this.keySet())
+ if (k.equalsIgnoreCase((String) key))
+ return true;
+ return false;
+ }
+
+ @Override
+ public List get(Object key) {
+ for (String k : this.keySet())
+ if (k.equalsIgnoreCase((String) key))
+ return super.get(k);
+ return null;
+ }
+
+ @Override
+ public List put(String key, List value) {
+ List previous = this.remove(key);
+ super.put(key, value);
+ return previous;
+ }
+
+ @Override
+ public void putAll(Map extends String, ? extends List> map) {
+ for (Map.Entry extends String, ? extends List> e : map
+ .entrySet())
+ this.put(e.getKey(), e.getValue());
+ }
+
+ @Override
+ public List remove(Object key) {
+ for (String k : this.keySet())
+ if (k.equalsIgnoreCase((String) key))
+ return super.remove(k);
+ return null;
+ }
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/Multipart.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/Multipart.java
new file mode 100644
index 0000000000..08c328ac19
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/Multipart.java
@@ -0,0 +1,72 @@
+package org.restlet.ext.odata.batch.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jvnet.mimepull.MIMEPart;
+import org.restlet.data.MediaType;
+
+
+/**
+ * The Class Multipart is logical representation of the multipart batch request.
+ *
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class Multipart extends BodyPart {
+
+ /**
+ * Instantiates a new multipart.
+ */
+ public Multipart() {
+ super();
+ }
+
+ /**
+ * Instantiates a new multipart.
+ *
+ * @param mimePart
+ * the mime part
+ */
+ public Multipart(MIMEPart mimePart) {
+ super(mimePart);
+ }
+
+ /** The body parts. */
+ List bodyParts = new ArrayList();
+
+ /**
+ * Gets the body parts.
+ *
+ * @return the body parts
+ */
+ public List getBodyParts() {
+ return bodyParts;
+ }
+
+ /**
+ * Adds the body parts.
+ *
+ * @param bodyPart
+ * the body part
+ */
+ public void addBodyParts(BodyPart bodyPart) {
+ // sets the parent multipart on the bodypart and then adds it to the
+ // list
+ bodyPart.setParent(this);
+ this.bodyParts.add(bodyPart);
+ }
+
+
+ @Override
+ public void setMediaType(MediaType mediaType) {
+
+ if (!mediaType.isCompatible(MediaType.MULTIPART_MIXED)) {
+ throw new IllegalArgumentException(mediaType.toString());
+ }
+ super.setMediaType(mediaType);
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/RestletBatchRequestHelper.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/RestletBatchRequestHelper.java
new file mode 100644
index 0000000000..2201801c7c
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/batch/util/RestletBatchRequestHelper.java
@@ -0,0 +1,385 @@
+package org.restlet.ext.odata.batch.util;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.jvnet.mimepull.Header;
+import org.jvnet.mimepull.MIMEMessage;
+import org.jvnet.mimepull.MIMEPart;
+import org.restlet.Request;
+import org.restlet.data.MediaType;
+import org.restlet.data.Method;
+import org.restlet.data.Reference;
+import org.restlet.engine.header.HeaderConstants;
+import org.restlet.ext.atom.Entry;
+import org.restlet.ext.atom.Feed;
+import org.restlet.ext.odata.Service;
+import org.restlet.ext.odata.batch.request.BatchProperty;
+import org.restlet.ext.odata.batch.request.ChangeSetRequest;
+import org.restlet.ext.odata.batch.request.ClientBatchRequest;
+import org.restlet.ext.odata.batch.request.impl.CreateEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.GetEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.ext.odata.batch.response.impl.BatchResponseImpl;
+import org.restlet.ext.odata.batch.response.impl.ChangeSetResponseImpl;
+import org.restlet.ext.odata.internal.edm.Metadata;
+import org.restlet.ext.odata.xml.AtomFeedHandler;
+import org.restlet.representation.Representation;
+import org.restlet.representation.StringRepresentation;
+
+/**
+ * The Class RestletBatchRequestHelper is helper class.
+ * It has some important functions like parsing changesets responses and
+ * formatting single requests. Validating the classname from a metadata before
+ * adding the entity.
+ *
+ * copyright 2014 Halliburton
+ *
+ * @author Amit.Jahagirdar
+ */
+public class RestletBatchRequestHelper {
+
+ /**
+ * Format single request.
+ *
+ * Creates a String out of the request and the format type provided.
+ *
+ * @param req
+ * the req
+ * @param formatType
+ * the format type
+ * @return the string
+ */
+ public static String formatSingleRequest(Request req, MediaType formatType) {
+
+ StringBuilder sb = new StringBuilder();
+ boolean userDefinedContentType = false;
+ sb.append(HeaderConstants.HEADER_CONTENT_TYPE).append(": ");
+
+ sb.append(MediaType.APPLICATION_ALL).append(BatchConstants.NEW_LINE);
+ sb.append(HeaderConstants.HEADER_TRANSFER_ENCODING).append(": ")
+ .append("Binary").append(BatchConstants.NEW_LINE);
+ sb.append(BatchConstants.NEW_LINE);
+
+ Reference resourceRef = req.getResourceRef();
+ String url = resourceRef.getIdentifier();
+
+ // now, adding this request, 1st URL
+ sb.append(req.getMethod()).append(" ").append(url)
+ .append(" HTTP/1.1\r\n");
+
+ if (!userDefinedContentType
+ && !(req.getMethod().equals(Method.GET) || req.getMethod()
+ .equals(Method.DELETE))) {
+
+ sb.append(HeaderConstants.HEADER_CONTENT_TYPE).append(": ")
+ .append(formatType + BatchConstants.FORMAT_TYPE_CHARSET_UTF8).append(BatchConstants.NEW_LINE);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Validate and return entity set name.
+ *
+ * This method validates if a entityType of the entityClass exists in the metadata for the given service.
+ *
+ * If exists then returns the EntitySetName
+ * else throws an exception.
+ *
+ *
+ * @param service
+ * the service
+ * @param entity
+ * the entity
+ * @return the string
+ * @throws Exception
+ * the exception
+ */
+ public static String validateAndReturnEntitySetName(Service service,
+ Class> entityClass) throws Exception {
+ Object object = null;
+ try {
+ object = service.getMetadata();
+ return ((Metadata) object).getEntityType(entityClass).getName();
+ } catch (SecurityException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new Exception("Can't add entity to this entity set "
+ + entityClass.getName()
+ + " due to lack of the service's metadata.");
+ }
+ }
+
+ /**
+ * Gets the entity sub path.
+ *
+ * @param service
+ * the service
+ * @param entity
+ * the entity
+ * @return the entity sub path
+ * @throws Exception
+ * the exception
+ */
+ public static String getEntitySubPath(Service service, Object entity)
+ throws Exception {
+ Object object = null;
+ try {
+ object = service.getMetadata();
+ return ((Metadata) object).getSubpath(entity).replace("/", "");
+ } catch (SecurityException e) {
+ throw e;
+ }
+ }
+
+ /**
+ * Gets the string representation.
+ *
+ * @param service
+ * the service
+ * @param entitySetName
+ * the entity set name
+ * @param entry
+ * the entry
+ * @return the string representation
+ */
+ public static StringRepresentation getStringRepresentation(Service service,
+ String entitySetName, Entry entry,MediaType type) {
+ if (entry != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ entry.write(baos);
+ baos.flush();
+ } catch (IOException e) {
+ new RuntimeException("IOException during creating a string representation"+ e);
+ }
+
+ StringRepresentation r = new StringRepresentation(baos.toString(),type);
+ return r;
+ }
+ return null;
+ }
+
+ /**
+ * Parses the single operation response.
+ *
+ * This method parses the response for a single request within the changeset or a singel GET request.
+ * Then creates a batch response and populates the entity by parsing the response output.
+ *
+ * @param topVersion
+ * the top version
+ * @param content
+ * the content
+ * @param so
+ * the so
+ * @param formatType
+ * the format type
+ * @param service
+ * the service
+ * @return the batch response
+ */
+ public static BatchResponse parseSingleOperationResponse(String topVersion,
+ String content, ClientBatchRequest so, MediaType formatType,
+ Service service) {
+ // first create a buffered reader
+ BufferedReader reader = new BufferedReader(new StringReader(content));
+ try {
+ // 1st line should be status line line HTTP/1.1 200 OK
+ String line = reader.readLine();
+ String[] statusLine = line.split("\\s");
+ int status = Integer.parseInt(statusLine[1]);
+
+ boolean isHeader = true;
+ Map headers = new HashMap();
+ MultivaluedMap inboundHeaders = new HeaderMap();
+ StringBuilder sb = new StringBuilder();
+ while ((line = reader.readLine()) != null) {
+ // \n\n indicates the end of header for the response
+ if (line.isEmpty()) {
+ isHeader = false;
+ continue;
+ }
+ if (isHeader) {
+ int idx = line.indexOf(":");
+ String key = line.substring(0, idx).toUpperCase().trim();
+ String value = line.substring(idx + 1).trim();
+ headers.put(key, value);
+ inboundHeaders.add(key, value);
+ } else {
+ sb.append(line);
+ }
+ }
+
+ Object result = null;
+ if (inboundHeaders.containsKey(BatchConstants.HTTP_HEADER_CONTENT_TYPE)) {
+ if (so instanceof CreateEntityRequest
+ || so instanceof GetEntityRequest) {
+ BatchProperty bp = (BatchProperty) so;
+ AtomFeedHandler aFHandler = new AtomFeedHandler(
+ bp.getEntitySetName(), bp.getEntityType(),
+ bp.getEntityClass(),
+ (Metadata) service.getMetadata());
+ result = RestletBatchRequestHelper.getEntity(
+ new StringRepresentation(sb.toString()), aFHandler);
+ }
+ }
+ BatchResponseImpl batchResponse = new BatchResponseImpl(status,
+ inboundHeaders, result);
+ return batchResponse;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "IOException in ParseSingleOperationResponse", e);
+ }
+
+ }
+
+ /**
+ * Parses the change set response.
+ * This method parses the response and from within parses each request within the changeset
+ * and creates a complete changeset response out of it.
+ *
+ * @param oDataVersion
+ * the o data version
+ * @param contentList
+ * the content list
+ * @param csr
+ * the csr
+ * @param formatType
+ * the format type
+ * @param service
+ * the service
+ * @return the batch response
+ */
+ public static BatchResponse parseChangeSetResponse(String oDataVersion,
+ List contentList, ChangeSetRequest csr,
+ MediaType formatType, Service service) {
+ // the change set will return another list of the result
+ ChangeSetResponse changeSetResponse = new ChangeSetResponseImpl();
+ int j = 0;
+ for (String content : contentList) {
+ ClientBatchRequest so = csr.getReqs().get(j);
+ BatchResponse response = RestletBatchRequestHelper
+ .parseSingleOperationResponse(oDataVersion, content, so,
+ formatType, service);
+ changeSetResponse.add(response);
+ j++;
+ }
+ return changeSetResponse;
+ }
+
+ /**
+ * Gets the entity by parsing the representation using the feedhandler sent as a parameter.
+ *
+ * @param
+ * the generic type
+ * @param rep
+ * the rep
+ * @param feedHandler
+ * the feed handler
+ * @return the entity
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public static T getEntity(Representation rep,
+ AtomFeedHandler feedHandler) throws IOException {
+ Feed feed = new Feed();
+ feedHandler.setFeed(feed);
+ feedHandler.parse(rep.getReader());
+ return feedHandler.getEntities().get(0);
+ }
+
+
+ /**
+ * Gets the string from input stream.
+ *
+ * @param is
+ * the is
+ * @return the string from input stream
+ */
+ public static String getStringFromInputStream(InputStream is) {
+ BufferedReader br = null;
+ StringBuilder sb = new StringBuilder();
+ String line;
+ try {
+ br = new BufferedReader(new InputStreamReader(is));
+ while ((line = br.readLine()) != null) {
+ sb.append(line).append(BatchConstants.NEW_LINE);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("IOException occured while resding stream"+ e);
+ } finally {
+ if (br != null) {
+ try {
+ // br.close();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Creates the multipart.
+ *
+ * A Multipart is a logical representation of a batch request or Chnagset.
+ * It is a set of multiple http requests/response.
+ *
+ * @param is
+ * the is
+ * @param mediaType
+ * the media type
+ * @return the multipart
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public static Multipart createMultipart(InputStream is, MediaType mediaType)
+ throws IOException {
+ // create a multipart
+ Multipart multipart = new Multipart();
+ // set its mediatype
+ multipart.setMediaType(mediaType);
+
+ MIMEMessage mimeMessage = new MIMEMessage(is, mediaType.getParameters()
+ .getFirstValue(BatchConstants.BATCH_BOUNDARY));
+ List attachments = mimeMessage.getAttachments();
+ for (MIMEPart mimePart : attachments) {
+ BodyPart bodyPart = new BodyPart(mimePart);
+ // copy headers into bodyparts
+ copyHeaders(bodyPart, mimePart);
+ bodyPart.setMediaType(new MediaType(bodyPart.getHeaders().getFirst(
+ BatchConstants.HTTP_HEADER_CONTENT_TYPE)));
+ multipart.addBodyParts(bodyPart);
+
+ }
+ return multipart;
+ }
+
+ /**
+ * Copies header information from mimePart to body part.
+ *
+ * @param bodyPart
+ * the body part
+ * @param mimePart
+ * the mime part
+ */
+ public static void copyHeaders(BodyPart bodyPart, MIMEPart mimePart) {
+ MultivaluedMap bpHeaders = bodyPart.getHeaders();
+ List extends Header> mHeaders = mimePart.getAllHeaders();
+ for (Header header : mHeaders) {
+ bpHeaders.add(header.getName(), header.getValue());
+ }
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/AtomContentFunctionHandler.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/AtomContentFunctionHandler.java
new file mode 100644
index 0000000000..fe5a5b79f9
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/AtomContentFunctionHandler.java
@@ -0,0 +1,74 @@
+package org.restlet.ext.odata.internal;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.restlet.Context;
+import org.restlet.ext.odata.internal.edm.TypeUtils;
+import org.restlet.ext.xml.format.XmlFormatParser;
+import org.restlet.representation.Representation;
+
+/**
+ * This class is added for parsing the representation result provided by RESLET as a response in the
+ * respective object/ return type for the functions/actions.
+ *
+ * @author Akshay
+ */
+public class AtomContentFunctionHandler extends XmlFormatParser implements FunctionContentHandler {
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.internal.FunctionContentHandler#parseResult(java.lang.Class, org.restlet.representation.Representation,
+ * java.lang.String, java.util.List)
+ */
+ @SuppressWarnings({ "unused", "unchecked", "rawtypes" })
+ public Object parseResult(Class> classType,
+ Representation representation, String functionName, List> entity) {
+ try {
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ XMLEventReader reader = factory.createXMLEventReader(representation.getReader());
+
+ while (reader.hasNext()) {
+ XMLEvent event = reader.nextEvent();
+ StartElement startElement = null;
+
+ if (event.isEndElement()
+ && startElement != null
+ && event.asEndElement().getName()
+ .equals(startElement.getName())) {
+ break;
+ }
+
+ if (isStartElement(event, new QName(XmlFormatParser.NS_DATASERVICES, functionName))) {
+ startElement = event.asStartElement();
+ }
+
+ if (event.isStartElement()
+ && event.asStartElement().getName().getNamespaceURI()
+ .equals(NS_DATASERVICES)
+ && event.asStartElement().getName()
+ .equals(DATASERVICES_ELEMENT)) {
+ if (entity instanceof List) {
+ Object value = TypeUtils.convert(classType,
+ reader.getElementText());
+ ((List) entity).add(value);
+ }
+ }
+ }
+ } catch (XMLStreamException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the xml due to Stream Exception: " + e.getMessage());
+ } catch (IOException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the xml due to IO Exception: " + e.getMessage());
+ }
+ return entity;
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/FunctionContentHandler.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/FunctionContentHandler.java
new file mode 100644
index 0000000000..4621eef07b
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/FunctionContentHandler.java
@@ -0,0 +1,26 @@
+package org.restlet.ext.odata.internal;
+import java.util.List;
+
+import org.restlet.representation.Representation;
+
+
+/**
+ * The interface for parsing the representation result provided by RESLET as a response in the
+ * respective object/ return type for the functions/actions.
+ *
+ * @author Shantanu
+ *
+ */
+public interface FunctionContentHandler {
+
+ /**
+ * Parses the result.
+ *
+ * @param classType - Class>
+ * @param representation - Representation
+ * @param functionName - Name of the function
+ * @param returnType - The return type
+ * @return expected result object for a function or action
+ */
+ Object parseResult(Class> classType, Representation representation, String functionName, List> returnType);
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/JsonContentFunctionHandler.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/JsonContentFunctionHandler.java
new file mode 100644
index 0000000000..84def9163a
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/JsonContentFunctionHandler.java
@@ -0,0 +1,95 @@
+package org.restlet.ext.odata.internal;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.XMLEvent;
+
+import org.restlet.Context;
+import org.restlet.ext.odata.xml.AtomFeedHandler;
+import org.restlet.ext.xml.format.XmlFormatParser;
+import org.restlet.representation.Representation;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+
+
+/**
+ * This class is added for parsing the representation result provided by RESLET as a response in the
+ * expected object/return type for the functions/actions.
+ *
+ * @author Shantanu
+ */
+public class JsonContentFunctionHandler extends XmlFormatParser implements FunctionContentHandler {
+
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.odata.internal.FunctionContentHandler#parseResult(java.lang.Class, org.restlet.representation.Representation,
+ * java.lang.String, java.util.List)
+ */
+ public Object parseResult(Class> c, Representation representation, String functionName,List> entity) {
+ try {
+ String jsonString = null;
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ XMLEventReader eventReader;
+ eventReader = factory.createXMLEventReader(representation.getReader());
+
+ while (eventReader.hasNext()) {
+ XMLEvent event;
+ event = eventReader.nextEvent();
+ if(isStartElement(event, new QName(XmlFormatParser.NS_DATASERVICES, functionName))){
+ jsonString = AtomFeedHandler.innerText(eventReader, event.asStartElement());
+ }
+ }
+
+ if (jsonString != null && !jsonString.equals("")) {
+ StringBuilder jsonStrBuilder = new StringBuilder();
+ jsonStrBuilder.append("{");
+ int beginIndex = jsonString.indexOf("{");
+ int endIndex = jsonString.indexOf("}");
+ String jsonStringWithoutBraces = jsonString.substring(beginIndex + 1, endIndex);
+
+ if (jsonStringWithoutBraces != null) {
+ String[] propertiesSplit = jsonStringWithoutBraces.trim().split(",");
+
+ for (int i = 0; i < propertiesSplit.length; i++) {
+ String value = propertiesSplit[i];
+
+ if (value.contains(":")) {
+ String[] split = value.trim().split(":");
+ String valueToNormalise = split[0].trim();
+ String normalisedValue = valueToNormalise.substring(0, 1)
+ + valueToNormalise.substring(1, 2).toLowerCase()
+ + valueToNormalise.substring(2);
+ jsonStrBuilder.append(normalisedValue);
+ jsonStrBuilder.append(":");
+ jsonStrBuilder.append(split[1]);
+ }
+
+ if (!(i == (propertiesSplit.length - 1))) {
+ jsonStrBuilder.append(",");
+ }
+ }
+ }
+
+ jsonStrBuilder.append("}");
+ return new Gson().fromJson(jsonStrBuilder.toString(), c);
+ }
+ } catch (XMLStreamException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the xml due to Stream Exception: " + e.getMessage());
+ } catch (IOException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the xml due to IO Exception: " + e.getMessage());
+ } catch (JsonSyntaxException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the xml due to Json Syntax Exception: " + e.getMessage());
+ }
+ return null;
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/EntityType.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/EntityType.java
index 073803f4a2..82c5029c0f 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/EntityType.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/EntityType.java
@@ -129,6 +129,7 @@ public Set getImportedJavaClasses() {
for (NavigationProperty property : getAssociations()) {
if (property.getToRole().isToMany()) {
result.add("java.util.List");
+ result.add("java.util.ArrayList");
break;
}
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/FunctionImport.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/FunctionImport.java
index b5a036fcfd..a9c5250bca 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/FunctionImport.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/FunctionImport.java
@@ -68,6 +68,32 @@ public class FunctionImport extends NamedObject {
/** The return type of this function. */
private String returnType;
+
+ /** The java return type of this function. */
+ private String javaReturnType;
+
+ /** The is complex. */
+ private boolean complex;
+
+ /** The is collection. */
+ private boolean collection;
+
+ /** The is simple. */
+ private boolean simple;
+
+ /**
+ * @return the javaReturnType
+ */
+ public String getJavaReturnType() {
+ return javaReturnType;
+ }
+
+ /**
+ * @param javaReturnType the javaReturnType to set
+ */
+ public void setJavaReturnType(String javaReturnType) {
+ this.javaReturnType = javaReturnType;
+ }
/**
* Constructor.
@@ -298,4 +324,47 @@ public void setReturnType(String returnType) {
this.returnType = returnType;
}
+ /**
+ * @return the isComplex
+ */
+ public boolean isComplex() {
+ return complex;
+ }
+
+ /**
+ * @param isComplex the isComplex to set
+ */
+ public void setComplex(boolean isComplex) {
+ this.complex = isComplex;
+ }
+
+ /**
+ * @return the isCollection
+ */
+ public boolean isCollection() {
+ return collection;
+ }
+
+ /**
+ * @param isCollection the isCollection to set
+ */
+ public void setCollection(boolean isCollection) {
+ this.collection = isCollection;
+ }
+
+ /**
+ * @return the isSimple
+ */
+ public boolean isSimple() {
+ return simple;
+ }
+
+ /**
+ * @param isSimple the isSimple to set
+ */
+ public void setSimple(boolean isSimple) {
+ this.simple = isSimple;
+ }
+
+
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java
index d59a46f682..d930edf696 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java
@@ -335,6 +335,14 @@ public Property getProperty(Object entity, String propertyName) {
break;
}
}
+ for(ComplexProperty property : et.getComplexProperties()){
+ if (property.getName().equals(propertyName)
+ || property.getNormalizedName()
+ .equals(propertyName)) {
+ result = property;
+ break;
+ }
+ }
} else {
ComplexType ct = getComplexType(entity.getClass());
if (ct != null) {
@@ -346,6 +354,14 @@ public Property getProperty(Object entity, String propertyName) {
break;
}
}
+ for(ComplexProperty property : ct.getComplexProperties()){
+ if (property.getName().equals(propertyName)
+ || property.getNormalizedName()
+ .equals(propertyName)) {
+ result = property;
+ break;
+ }
+ }
}
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/MetadataReader.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/MetadataReader.java
index 564c632fa2..34051b127f 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/MetadataReader.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/MetadataReader.java
@@ -41,6 +41,8 @@
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.ext.odata.Service;
+import org.restlet.ext.odata.internal.reflect.ReflectUtils;
+import org.restlet.ext.xml.format.XmlFormatParser;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
@@ -561,13 +563,19 @@ public void startElement(String uri, String localName, String name,
if (type.toLowerCase().startsWith("edm.")) {
property = new Property(attrs.getValue("Name"));
property.setType(new Type(attrs.getValue("Type")));
+ property.setDefaultValue(attrs.getValue("Default"));
+ } else if (type.toLowerCase().startsWith("collection")) {
+ ComplexProperty p = new ComplexProperty(attrs.getValue("Name"));
+ String edmType = TypeUtils.getClassType(type);
+ p.setComplexType(new ComplexType("List<"+edmType+">"));
+ property = p;
+ property.setDefaultValue("new ArrayList<"+edmType+">()");
} else {
ComplexProperty p = new ComplexProperty(attrs.getValue("Name"));
p.setComplexType(new ComplexType(attrs.getValue("Type")));
property = p;
+ property.setDefaultValue(attrs.getValue("Default"));
}
-
- property.setDefaultValue(attrs.getValue("Default"));
// If no value is specified, the nullable facet defaults to true.
// cf
// http://www.odata.org/documentation/odata-v3-documentation/common-schema-definition-language-csdl/#531_The_edmNullable_Attribute
@@ -575,7 +583,11 @@ public void startElement(String uri, String localName, String name,
if (nullable == null) {
property.setNullable(true);
} else {
- property.setNullable(Boolean.parseBoolean(nullable));
+ boolean isNullable = Boolean.parseBoolean(nullable);
+ property.setNullable(isNullable);
+ if(!isNullable){
+ property.getAnnotations().add("NotNull");
+ }
}
// ConcurrencyMode
if ("fixed".equalsIgnoreCase(attrs.getValue("ConcurrencyMode"))) {
@@ -591,8 +603,32 @@ public void startElement(String uri, String localName, String name,
if (str != null) {
property.setMediaType(MediaType.valueOf(str));
}
-
- if (getState() == State.ENTITY_TYPE) {
+
+ String systemGenerated = attrs.getValue(
+ XmlFormatParser.NS_CUSTOM_EDMANNOTATION, "IsSystemGenerated");
+ if (systemGenerated != null) {
+ boolean isSystemGenerated = Boolean.parseBoolean(systemGenerated);
+ if(isSystemGenerated){
+ property.getAnnotations().add("SystemGenerated");
+ }
+ }
+
+ String propName = attrs.getValue("Name");
+ //add annotation to the property if it property name is same as java reserved key word.
+ if(propName!=null&&ReflectUtils.isReservedWord(propName.toLowerCase())){
+ property.getAnnotations().add("JavaReservedKeyWord");
+ }
+
+ if(currentEntityType!=null){
+ List keys = currentEntityType.getKeys();
+ for(Property prop : keys){
+ if(prop.getName().equalsIgnoreCase(attrs.getValue("Name"))){
+ property.getAnnotations().add("PrimaryKey");
+ }
+ }
+ }
+
+ if (getState() == State.ENTITY_TYPE) {
pushState(State.ENTITY_TYPE_PROPERTY);
if (property instanceof ComplexProperty) {
this.currentEntityType.getComplexProperties().add(
@@ -667,11 +703,45 @@ public void startElement(String uri, String localName, String name,
currentFunctionImport.setMethodAccess(attrs
.getValue("MethodAccess"));
currentFunctionImport.setMetadata(currentMetadata);
-
- String str = attrs.getValue(
+ String elementType = attrs.getValue(XmlFormatParser.NS_CUSTOM_EDMANNOTATION, "elementType");
+ if (elementType != null) {
+ String[] split = elementType.split("\\.");
+ String className = ReflectUtils.normalize(split[1]);
+ className = className.substring(0, 1).toUpperCase() + className.substring(1);
+ currentFunctionImport.setJavaReturnType(className);
+ currentFunctionImport.setComplex(true);
+ } else if (attrs.getValue("ReturnType") != null) {
+ if (attrs.getValue("ReturnType").startsWith("Collection")) {
+ String type = TypeUtils.getClassType(attrs.getValue("ReturnType"));
+ currentFunctionImport.setJavaReturnType("List<"+type+">");
+ currentFunctionImport.setReturnType(type);
+ currentFunctionImport.setCollection(true);
+ }else {
+ currentFunctionImport.setSimple(true);
+ currentFunctionImport.setJavaReturnType(TypeUtils
+ .toJavaTypeName(attrs.getValue("ReturnType")));
+ }
+ }else {
+ currentFunctionImport.setComplex(true);
+ currentFunctionImport.setJavaReturnType("void");
+ }
+
+
+ String httpMethod = attrs.getValue(
Service.WCF_DATASERVICES_METADATA_NAMESPACE, "HttpMethod");
- if (str != null) {
- currentFunctionImport.setMethod(Method.valueOf(str));
+ if (httpMethod != null) {
+ currentFunctionImport.setMethod(Method.valueOf(httpMethod));
+ }
+ else{
+ //Default to POST if isSideEffecting="true" and no Http method provided
+ Boolean isSideEffecting = Boolean.parseBoolean(attrs.getValue("IsSideEffecting"));
+ if(isSideEffecting){
+ currentFunctionImport.setMethod(Method.valueOf("POST"));
+ }
+ else{
+ //Default to GET is isSideEffecting="false" and no Http method provided
+ currentFunctionImport.setMethod(Method.valueOf("GET"));
+ }
}
if (State.ENTITY_CONTAINER == getState()) {
@@ -684,6 +754,12 @@ public void startElement(String uri, String localName, String name,
if (State.FUNCTION_IMPORT == getState()) {
Parameter parameter = new Parameter(attrs.getValue("Name"));
parameter.setType(attrs.getValue("Type"));
+ if(attrs.getValue("Type").startsWith("Collection")){
+ String edmType = TypeUtils.getClassType(attrs.getValue("Type"));
+ parameter.setJavaType("List<"+edmType+">");
+ }else{
+ parameter.setJavaType(TypeUtils.toJavaTypeName(attrs.getValue("Type")));
+ }
parameter.setMode(attrs.getValue("Mode"));
String str = attrs.getValue("MaxLength");
if (str != null) {
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/NamedObject.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/NamedObject.java
index e1d837745b..f57a47dcdf 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/NamedObject.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/NamedObject.java
@@ -58,7 +58,12 @@ public class NamedObject {
public NamedObject(String name) {
super();
this.name = name;
- this.normalizedName = ReflectUtils.normalize(name);
+ String normalizedName = ReflectUtils.normalize(name);
+ if (ReflectUtils.isReservedWord(normalizedName)) {
+ normalizedName = "_" + normalizedName;
+ }
+ this.normalizedName = normalizedName;
+
}
/**
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/ODataType.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/ODataType.java
index 5f58acb342..ad52a74065 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/ODataType.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/ODataType.java
@@ -145,12 +145,20 @@ public Set getImportedJavaClasses() {
}
for (ComplexProperty property : getComplexProperties()) {
- if (property.getComplexType() != null
- && property.getComplexType().getSchema() != null) {
- if (!property.getComplexType().getSchema().equals(getSchema())) {
- result.add(property.getComplexType().getFullClassName());
- }
- }
+ if (property.getComplexType() != null) {
+ if (property.getComplexType().getSchema() != null) {
+ if (!property.getComplexType().getSchema()
+ .equals(getSchema())) {
+ result.add(property.getComplexType().getFullClassName());
+ }
+ } else {
+ String propertyType = property.getComplexType().getName();
+ if (propertyType.toLowerCase().startsWith("list")) {
+ result.add("java.util.List");
+ result.add("java.util.ArrayList");
+ }
+ }
+ }
}
return result;
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Parameter.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Parameter.java
index dd0ae4e4a1..dbcb077c01 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Parameter.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Parameter.java
@@ -57,6 +57,9 @@ public class Parameter extends NamedObject {
/** The type of the parameter. */
private String type;
+
+ /** The type of the parameter. */
+ private String javaType;
/**
* Constructor.
@@ -163,4 +166,18 @@ public void setType(String type) {
this.type = type;
}
+ /**
+ * @return the javaType
+ */
+ public String getJavaType() {
+ return javaType;
+ }
+
+ /**
+ * @param javaType the javaType to set
+ */
+ public void setJavaType(String javaType) {
+ this.javaType = javaType;
+ }
+
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Property.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Property.java
index de65a82f11..085a0d2a16 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Property.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Property.java
@@ -33,6 +33,9 @@
package org.restlet.ext.odata.internal.edm;
+import java.util.ArrayList;
+import java.util.List;
+
import org.restlet.data.MediaType;
import org.restlet.ext.odata.internal.reflect.ReflectUtils;
@@ -65,6 +68,8 @@ public class Property extends NamedObject {
/** The type of the property. */
private Type type;
+
+ private List annotations = new ArrayList();
/**
* Constructor.
@@ -231,4 +236,17 @@ public void setType(Type type) {
this.type = type;
}
+ /**
+ * @return the annotations
+ */
+ public List getAnnotations() {
+ return annotations;
+ }
+
+ /**
+ * @param annotations the annotations to set
+ */
+ public void setAnnotations(List annotations) {
+ this.annotations = annotations;
+ }
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Type.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Type.java
index 630988094e..2da1772c83 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Type.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Type.java
@@ -76,6 +76,8 @@ public Set getImportedJavaClasses() {
result.add(getJavaClass().getName());
} else if (getName().endsWith("DateTimeOffset")) {
result.add(getJavaClass().getName());
+ } else if (getName().endsWith("Stream")) {
+ result.add(getJavaClass().getName());
}
return result;
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java
index 88c07c2d58..f54a5980d1 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java
@@ -33,6 +33,9 @@
package org.restlet.ext.odata.internal.edm;
+import java.beans.PropertyEditor;
+import java.beans.PropertyEditorManager;
+import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
@@ -45,6 +48,7 @@
import org.restlet.engine.util.Base64;
import org.restlet.engine.util.DateUtils;
import org.restlet.ext.odata.internal.reflect.ReflectUtils;
+import org.restlet.ext.odata.streaming.StreamReference;
/**
* Handle type operations.
@@ -102,11 +106,11 @@ public static Object fromEdm(String value, String adoNetType) {
} else if (adoNetType.endsWith("Time")) {
result = timeFormat.parseObject(value);
} else if (adoNetType.endsWith("Decimal")) {
- result = decimalFormat.parseObject(value);
+ result = BigDecimal.valueOf((Long) decimalFormat.parseObject(value));
} else if (adoNetType.endsWith("Single")) {
- result = singleFormat.parseObject(value);
+ result = Float.valueOf(singleFormat.parseObject(value).toString());
} else if (adoNetType.endsWith("Double")) {
- result = doubleFormat.parseObject(value);
+ result = Double.valueOf(doubleFormat.parseObject(value).toString());
} else if (adoNetType.endsWith("Guid")) {
result = value;
} else if (adoNetType.endsWith("Int16")) {
@@ -206,6 +210,9 @@ public static String getLiteralForm(String value, String adoNetType) {
result = "guid'" + value + "'";
} else if (adoNetType.endsWith("String")) {
result = "'" + value + "'";
+ }else if (adoNetType.endsWith("Double") || adoNetType.endsWith("Float")
+ || adoNetType.endsWith("Integer") || adoNetType.endsWith("Long")) {
+ result = value ;
}
} catch (Exception e) {
Context.getCurrentLogger().warning(
@@ -288,6 +295,8 @@ public static String toEdm(Object value, Type type) {
} else if (adoNetType.endsWith("Decimal")) {
if ((Double.class).isAssignableFrom(value.getClass())) {
result = toEdmDecimal((Double) value);
+ }else if ((BigDecimal.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDecimal((BigDecimal) value);
}
} else if (adoNetType.endsWith("Single")) {
if ((Float.class).isAssignableFrom(value.getClass())) {
@@ -386,6 +395,18 @@ public static String toEdmDateTime(Date value) {
public static String toEdmDecimal(double value) {
return decimalFormat.format(value);
}
+
+ /**
+ * Convert the given value to the String representation of a EDM Decimal
+ * value.
+ *
+ * @param value
+ * The value to convert.
+ * @return The value converted as String object.
+ */
+ public static String toEdmDecimal(BigDecimal value) {
+ return decimalFormat.format(value);
+ }
/**
* Convert the given value to the String representation of a EDM Double
@@ -475,6 +496,8 @@ public static String toEdmKey(Object value, Type type) {
} else if (adoNetType.endsWith("Decimal")) {
if ((Double.class).isAssignableFrom(value.getClass())) {
result = toEdmDecimal((Double) value);
+ } else if ((BigDecimal.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDecimal((BigDecimal) value);
}
} else if (adoNetType.endsWith("Single")) {
if ((Float.class).isAssignableFrom(value.getClass())) {
@@ -570,9 +593,9 @@ public static Class> toJavaClass(String edmTypeName) {
} else if (edmTypeName.endsWith("Time")) {
result = Long.class;
} else if (edmTypeName.endsWith("Decimal")) {
- result = Double.class;
+ result = BigDecimal.class;
} else if (edmTypeName.endsWith("Single")) {
- result = Double.class;
+ result = Float.class;
} else if (edmTypeName.endsWith("Double")) {
result = Double.class;
} else if (edmTypeName.endsWith("Guid")) {
@@ -587,6 +610,40 @@ public static Class> toJavaClass(String edmTypeName) {
result = Byte.class;
} else if (edmTypeName.endsWith("String")) {
result = String.class;
+ } else if (edmTypeName.startsWith("List")) {
+ result = List.class;
+ } else if (edmTypeName.endsWith("Stream")) {
+ result = StreamReference.class;
+ }
+
+ return result;
+ }
+
+ public static String toEdmType(String edmTypeName) {
+ String result = "Object";
+ edmTypeName = edmTypeName.toLowerCase();
+ if (edmTypeName.endsWith("byte")) {
+ result = "Edm.Byte";
+ } else if (edmTypeName.endsWith("boolean")) {
+ result = "Edm.Boolean";
+ } else if (edmTypeName.endsWith("date")) {
+ result = "Edm.DateTime";
+ } else if (edmTypeName.endsWith("bigdecimal")) {
+ result = "Edm.Decimal";
+ } else if (edmTypeName.endsWith("float")) {
+ result = "Edm.Single";
+ } else if (edmTypeName.endsWith("double")) {
+ result = "Edm.Double";
+ } else if (edmTypeName.endsWith("short")) {
+ result = "Edm.Int16";
+ } else if (edmTypeName.endsWith("integer")) {
+ result = "Edm.Int32";
+ } else if (edmTypeName.endsWith("long")) {
+ result = "Edm.Int64";
+ } else if (edmTypeName.endsWith("string")) {
+ result = "Edm.String";
+ } else if (edmTypeName.endsWith("streamreference")) {
+ result = "Edm.Stream";
}
return result;
@@ -604,7 +661,7 @@ public static String toJavaTypeName(String edmTypeName) {
if (edmTypeName.endsWith("Binary")) {
result = "byte[]";
} else if (edmTypeName.endsWith("Boolean")) {
- result = "boolean";
+ result = "Boolean";
} else if (edmTypeName.endsWith("DateTime")) {
result = "Date";
} else if (edmTypeName.endsWith("DateTimeOffset")) {
@@ -612,26 +669,86 @@ public static String toJavaTypeName(String edmTypeName) {
} else if (edmTypeName.endsWith("Time")) {
result = "long";
} else if (edmTypeName.endsWith("Decimal")) {
- result = "double";
+ result = "java.math.BigDecimal";
} else if (edmTypeName.endsWith("Single")) {
- result = "double";
+ result = "Float";
} else if (edmTypeName.endsWith("Double")) {
- result = "double";
+ result = "Double";
} else if (edmTypeName.endsWith("Guid")) {
result = "String";
} else if (edmTypeName.endsWith("Int16")) {
- result = "short";
+ result = "Short";
} else if (edmTypeName.endsWith("Int32")) {
- result = "int";
+ result = "Integer";
} else if (edmTypeName.endsWith("Int64")) {
- result = "long";
+ result = "Long";
} else if (edmTypeName.endsWith("Byte")) {
- result = "byte";
+ result = "Byte";
} else if (edmTypeName.endsWith("String")) {
result = "String";
+ } else if (edmTypeName.endsWith("Stream")) {
+ result = "StreamReference";
}
return result;
}
+
+ /**
+ * Gets the class type.
+ *
+ * @param Edm Type. For e.g. Edm.Double
+ * @return the respective java class. For e.g. java.lang.Double in case of Edm.Double
+ */
+ public static String getClassType(String type) {
+ try {
+ String edmType = TypeUtils.getCollectionType(type);
+ if (edmType == null){
+ return null;
+ }
+ if (edmType.toLowerCase().startsWith("edm.")) {
+ Class> javaClass = TypeUtils.toJavaClass(edmType);
+ return javaClass.getName();
+ } else {
+ String[] split = edmType.split("\\.");
+ StringBuilder sb = new StringBuilder();
+ for (int i = 1; i < split.length; i++) {
+ sb.append(split[i]);
+ }
+ return sb.toString();
+ }
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the collection type.
+ *
+ * @param String as per metadata. For e.g. Collection(Edm.Double)
+ * @return the respective edm type. For e.g. Edm.Double in case of Collection(Edm.Double)
+ */
+ public static String getCollectionType(String type){
+ if(type != null && type.length()>11){
+ return type.substring(11, type.length() - 1);
+ }
+ return null;
+ }
+
+ /**
+ * Convert the String value to primitive class type.
+ *
+ * @param targetType the target type
+ * @param text the text
+ * @return the object
+ */
+ public static Object convert(Class> targetType, String text) {
+ try {
+ PropertyEditor editor = PropertyEditorManager.findEditor(targetType);
+ editor.setAsText(text);
+ return editor.getValue();
+ } catch (Exception e) {
+ return text;
+ }
+ }
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java
index 5fb06721ff..3b2796975f 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java
@@ -253,6 +253,7 @@ public static void invokeSetter(Object entity, String propertyName,
if ((method.getParameterTypes() != null)
&& (method.getParameterTypes().length == 1)) {
setter = method;
+ break;
}
}
}
@@ -368,6 +369,9 @@ public static boolean isReservedWord(String name) {
*/
public static String normalize(String name) {
String result = null;
+ if(name != null && name.toLowerCase().startsWith("list")){
+ return name;
+ }
if (name != null) {
// Build the normalized name according to the java naming rules
StringBuilder b = new StringBuilder();
@@ -525,4 +529,32 @@ public static void setProperty(Object entity, String propertyName,
invokeSetter(entity, propertyName, propertyValue, null);
}
+
+ /**
+ * Gets the property object.
+ * Creates the instance of property if not already created.
+ *
+ * @param the generic type
+ * @param entity the entity
+ * @param propertyName the property name
+ * @return the property object
+ */
+ public static Object getPropertyObject(T entity, String propertyName) {
+ Object o = null;
+ try {
+ o = ReflectUtils.invokeGetter(entity, propertyName);
+ Field[] fields = entity.getClass().getDeclaredFields();
+ if (o == null) {
+ for (Field field : fields) {
+ if (field.getName().equalsIgnoreCase(propertyName)) {
+ o = field.getType().newInstance();
+ break;
+ }
+ }
+ }
+ } catch (Exception e) {
+ logger.warning("Can't get the property: " + e.getMessage());
+ }
+ return o;
+ }
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/complexType.ftl b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/complexType.ftl
index 02a4fb9792..fdabb14fd1 100755
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/complexType.ftl
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/complexType.ftl
@@ -64,9 +64,9 @@ public <#if type.abstractType>abstract #if>class ${className} {
#list>
<#list type.complexProperties?sort_by("name") as property>
<#if property.complexType??>
- private ${property.complexType.className} ${property.propertyName};
+ private ${property.complexType.className} ${property.propertyName}<#if property.defaultValue??> = ${property.defaultValue}#if>;
<#else>
- // private [error: no defined type] ${property.propertyName};
+ // private [error: no defined type] ${property.propertyName}<#if property.defaultValue??> = ${property.defaultValue}#if>;
#if>
#list>
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/entityType.ftl b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/entityType.ftl
index 853e3e152c..889f347b22 100755
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/entityType.ftl
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/entityType.ftl
@@ -40,10 +40,14 @@ import ${clazz};
#list>
<#list type.importedTypes?sort as t>
-import ${t.fullClassName};
+import ${packageName}.${t.className};
#list>
#compress>
+import org.restlet.ext.odata.validation.annotation.NotNull;
+import org.restlet.ext.odata.validation.annotation.PrimaryKey;
+import org.restlet.ext.odata.validation.annotation.SystemGenerated;
+import org.restlet.ext.odata.validation.annotation.JavaReservedKeyWord;
<#compress>
/**
@@ -57,6 +61,9 @@ import ${t.fullClassName};
public <#if type.abstractType>abstract #if>class ${className} {
<#list type.properties?sort_by("name") as property>
+ <#list property.annotations as annotation>
+ @${annotation}
+ #list>
<#if property.type??>
private ${property.type.className} ${property.propertyName}<#if property.defaultValue??> = property.defaultValue#if>;
<#else>
@@ -65,13 +72,13 @@ public <#if type.abstractType>abstract #if>class ${className} {
#list>
<#list type.complexProperties?sort_by("name") as property>
<#if property.complexType??>
- private ${property.complexType.className} ${property.propertyName};
+ private ${property.complexType.className} ${property.propertyName}<#if property.defaultValue??> = ${property.defaultValue}#if>;;
<#else>
- // private [error: no defined type] ${property.propertyName};
+ // private [error: no defined type] ${property.propertyName}<#if property.defaultValue??> = ${property.defaultValue}#if>;;
#if>
#list>
<#list type.associations?sort_by("name") as association>
- private <#if association.toRole.toMany>List<${association.toRole.type.className}><#else>${association.toRole.type.className}#if> ${association.normalizedName};
+ private <#if association.toRole.toMany> List<${association.toRole.type.className}> <#else> ${association.toRole.type.className} #if> ${association.normalizedName} <#if association.toRole.toMany> = new ArrayList<${association.toRole.type.className}>()#if>;
#list>
<#if type.blob>
/** The reference of the underlying blob representation. */
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/service.ftl b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/service.ftl
index c9958fb271..373be94a2c 100755
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/service.ftl
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/templates/service.ftl
@@ -30,9 +30,11 @@
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
+package ${packageName};
+import java.util.ArrayList;
import java.util.List;
-
+import java.util.Collection;
import org.restlet.data.MediaType;
import org.restlet.data.Preference;
import org.restlet.data.Reference;
@@ -40,9 +42,25 @@ import org.restlet.ext.odata.Query;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
+import org.restlet.data.ChallengeScheme;
+import org.restlet.data.ChallengeResponse;
+import org.restlet.data.Parameter;
+import org.restlet.util.Series;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.restlet.ext.odata.internal.edm.TypeUtils;
+import org.restlet.ext.odata.internal.FunctionContentHandler;
+import org.restlet.ext.odata.internal.JsonContentFunctionHandler;
+import org.restlet.ext.odata.internal.AtomContentFunctionHandler;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.BatchRequestImpl;
<#list entityContainer.entities?sort as entitySet>
-import ${entitySet.type.fullClassName};
+import ${entityClassPkg}.${entitySet.type.className};
+#list>
+
+<#list schema.complexTypes? sort as ct>
+import ${entityClassPkg}.${ct.className};
#list>
<#compress>
@@ -56,12 +74,46 @@ import ${entitySet.type.fullClassName};
public class ${className} extends org.restlet.ext.odata.Service {
- /**
- * Constructor.
- *
- */
+ FunctionContentHandler functionContentHandler;
+
+ /**
+ * Constructor.
+ *
+ */
public ${className}() {
super("${dataServiceUri}");
+ this.functionContentHandler = new JsonContentFunctionHandler();
+ <#if challengeScheme??>
+ super.setCredentials(new ChallengeResponse(${challengeScheme}, "${userName}", "${password}"));
+ #if>
+ }
+
+ <#if challengeScheme??>
+ public ${className}(String serviceUrl, String userName, String password) {
+ super(serviceUrl);
+ this.functionContentHandler = new JsonContentFunctionHandler();
+ super.setCredentials(new ChallengeResponse(${challengeScheme}, userName, password));
+ }
+ #if>
+
+ public ${className}(String serviceUrl, String userName, String password, ChallengeScheme cs) {
+ super(serviceUrl);
+ this.functionContentHandler = new JsonContentFunctionHandler();
+ super.setCredentials(new ChallengeResponse(cs, userName, password));
+ }
+
+ <#if challengeScheme??>
+ public ${className}(String serviceUrl, String userName, String password, FunctionContentHandler functionContentHandler) {
+ super(serviceUrl);
+ this.functionContentHandler = functionContentHandler;
+ super.setCredentials(new ChallengeResponse(${challengeScheme}, userName, password));
+ }
+ #if>
+
+ public ${className}(String serviceUrl, String userName, String password, ChallengeScheme cs, FunctionContentHandler functionContentHandler) {
+ super(serviceUrl);
+ this.functionContentHandler = functionContentHandler;
+ super.setCredentials(new ChallengeResponse(cs, userName, password));
}
<#list entityContainer.entities as entitySet>
@@ -71,10 +123,13 @@ public class ${className} extends org.restlet.ext.odata.Service {
*
* @param entity
* The entity to add to the service.
+ * @return entity Type Object
+ * The newly created entity.
+ *
* @throws Exception
*/
- public void addEntity(${type.fullClassName} entity) throws Exception {
- <#if entityContainer.defaultEntityContainer>addEntity("/${entitySet.name}", entity);<#else>addEntity("/${entityContainer.name}.${entitySet.name}", entity);#if>
+ public ${type.className} addEntity(${type.className} entity) throws Exception {
+ return <#if entityContainer.defaultEntityContainer>addEntity("/${entitySet.name}", entity);<#else>addEntity("/${entityContainer.name}.${entitySet.name}", entity);#if>
}
/**
@@ -84,8 +139,8 @@ public class ${className} extends org.restlet.ext.odata.Service {
* The path to this entity relatively to the service URI.
* @return A query object.
*/
- public Query<${type.fullClassName}> create${type.className}Query(String subpath) {
- return createQuery(subpath, ${type.fullClassName}.class);
+ public Query<${type.className}> create${type.className}Query(String subpath) {
+ return createQuery(subpath, ${type.className}.class);
}
<#if (type.blob && type.blobValueRefProperty?? && type.blobValueRefProperty.name??)>
@@ -96,7 +151,7 @@ public class ${className} extends org.restlet.ext.odata.Service {
* The given media resource.
* @return The binary representation of the given media resource.
*/
- public Representation getValue(${type.fullClassName} entity) throws ResourceException {
+ public Representation getValue(${type.className} entity) throws ResourceException {
Reference ref = getValueRef(entity);
if (ref != null) {
ClientResource cr = createResource(ref);
@@ -115,7 +170,7 @@ public class ${className} extends org.restlet.ext.odata.Service {
* The requested media types of the representation.
* @return The given media resource.
*/
- public Representation getValue(${type.fullClassName} entity,
+ public Representation getValue(${type.className} entity,
List> acceptedMediaTypes)
throws ResourceException {
Reference ref = getValueRef(entity);
@@ -137,7 +192,7 @@ public class ${className} extends org.restlet.ext.odata.Service {
* The requested media type of the representation
* @return The given media resource.
*/
- public Representation getValue(${type.fullClassName} entity, MediaType mediaType)
+ public Representation getValue(${type.className} entity, MediaType mediaType)
throws ResourceException {
Reference ref = getValueRef(entity);
if (ref != null) {
@@ -155,7 +210,7 @@ public class ${className} extends org.restlet.ext.odata.Service {
* The media resource.
* @return The reference of the binary representation of the given entity.
*/
- public Reference getValueRef(${type.fullClassName} entity) {
+ public Reference getValueRef(${type.className} entity) {
if (entity != null) {
return entity.get${type.blobValueRefProperty.name?cap_first}();
}
@@ -172,7 +227,7 @@ public class ${className} extends org.restlet.ext.odata.Service {
* The new representation.
* @throws ResourceException
*/
- public void setValue(${type.fullClassName} entity, Representation blob)
+ public void setValue(${type.className} entity, Representation blob)
throws ResourceException {
Reference ref = entity.get${type.blobValueEditRefProperty.name?cap_first}();
@@ -182,6 +237,119 @@ public class ${className} extends org.restlet.ext.odata.Service {
}
}
#if>
+#list>
+ /**
+ * Returns the instance of BatchRequestImpl for batch requests.
+ *
+ * @return The reference of the binary representation of the given entity.
+ */
+ public BatchRequest createBatchRequest(){
+ return new BatchRequestImpl(this);
+ }
+
+<#list entityContainer.functionImports as functionImport>
+ <#if functionImport.complex>
+ public ${functionImport.javaReturnType} ${functionImport.name}(
+ <#assign i= functionImport.parameters?size>
+ <#list functionImport.parameters as parameter>
+ <#if i==1>
+ ${parameter.javaType} ${parameter.name}
+ <#else>
+ ${parameter.javaType} ${parameter.name},
+ #if>
+ <#assign i = i-1>
+ #list>) {
+ <#if functionImport.javaReturnType!="void">
+ ${functionImport.javaReturnType} ${functionImport.name} = null;
+ #if>
+ Series parameters = new Series(Parameter.class);
+ <#list functionImport.parameters as parameter>
+ Parameter param${parameter.name} = new Parameter();
+ param${parameter.name}.setName("${parameter.name}");
+ <#if parameter.type?starts_with("List") || parameter.type?starts_with("Collection")>
+ Gson gson = new GsonBuilder().serializeNulls().serializeSpecialFloatingPointValues().create();
+ String jsonValue=gson.toJson(${parameter.name});
+ param${parameter.name}.setValue(jsonValue);
+ <#else>
+ param${parameter.name}.setValue(${parameter.name}!=null?${parameter.name}.toString():null);
+ #if>
+ parameters.add(param${parameter.name});
+ #list>
+ <#if functionImport.javaReturnType!="void">
+ Representation representation = invokeComplex("${functionImport.name}", parameters);
+ ${functionImport.name} = (${functionImport.javaReturnType})this.functionContentHandler.parseResult(${functionImport.javaReturnType}.class, representation, "${functionImport.name}",null);
+ <#else>
+ invokeComplex("${functionImport.name}", parameters);
+ #if>
+ <#if functionImport.javaReturnType!="void">
+ return ${functionImport.name};
+ #if>
+ }
+ #if>
+
+ <#if functionImport.collection>
+ public ${functionImport.javaReturnType} ${functionImport.name}(
+ <#assign i= functionImport.parameters?size>
+ <#list functionImport.parameters as parameter>
+ <#if i==1>
+ ${parameter.javaType} ${parameter.name}
+ <#else>
+ ${parameter.javaType} ${parameter.name},
+ #if>
+ <#assign i = i-1>
+ #list>) {
+ <#if functionImport.javaReturnType!="void">
+ ${functionImport.javaReturnType} ${functionImport.name} = new ArrayList<${functionImport.returnType}>();
+ #if>
+ Series parameters = new Series(Parameter.class);
+ <#list functionImport.parameters as parameter>
+ Parameter param${parameter.name} = new Parameter();
+ param${parameter.name}.setName("${parameter.name}");
+ <#if parameter.type?starts_with("List") || parameter.type?starts_with("Collection")>
+ Gson gson = new GsonBuilder().serializeNulls().serializeSpecialFloatingPointValues().create();
+ String jsonValue=gson.toJson(${parameter.name});
+ param${parameter.name}.setValue(jsonValue);
+ <#else>
+ param${parameter.name}.setValue(${parameter.name}!=null?${parameter.name}.toString():null);
+ #if>
+ parameters.add(param${parameter.name});
+ #list>
+ <#if functionImport.javaReturnType!="void">
+ Representation representation = invokeComplex("${functionImport.name}", parameters);
+ ${functionImport.name} = (${functionImport.javaReturnType})this.functionContentHandler.parseResult(${functionImport.returnType}.class, representation, "${functionImport.name}", ${functionImport.name});
+ <#else>
+ invokeComplex("${functionImport.name}", parameters);
+ #if>
+ <#if functionImport.javaReturnType!="void">
+ return ${functionImport.name};
+ #if>
+ }
+ #if>
+
+ <#if functionImport.simple>
+ public ${functionImport.javaReturnType} ${functionImport.name} (
+ <#assign i= functionImport.parameters?size>
+ <#list functionImport.parameters as parameter>
+ <#if i==1>
+ ${parameter.javaType} ${parameter.name}
+ <#else>
+ ${parameter.javaType} ${parameter.name},
+ #if>
+ <#assign i = i-1>
+ #list>) throws ResourceException, Exception{
+ ${functionImport.javaReturnType} ${functionImport.name} = null;
+ Series parameters = new Series(Parameter.class);
+ <#list functionImport.parameters as parameter>
+ Parameter param${parameter.name} = new Parameter();
+ param${parameter.name}.setName("${parameter.name}");
+ param${parameter.name}.setValue(${parameter.name}!=null?${parameter.name}.toString():null);
+ parameters.add(param${parameter.name});
+ #list>
+ String stringValue = invokeSimple("${functionImport.name}", parameters);
+ ${functionImport.name} = (${functionImport.javaReturnType})TypeUtils.convert(${functionImport.javaReturnType}.class, stringValue);
+ return ${functionImport.name};
+ }
+ #if>
#list>
}
\ No newline at end of file
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/streaming/StreamReference.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/streaming/StreamReference.java
new file mode 100644
index 0000000000..1f8cfc308d
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/streaming/StreamReference.java
@@ -0,0 +1,177 @@
+package org.restlet.ext.odata.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.logging.Level;
+
+import org.restlet.Context;
+import org.restlet.data.Reference;
+import org.restlet.ext.odata.Service;
+import org.restlet.representation.Representation;
+import org.restlet.resource.ClientResource;
+
+/**
+ * This class stores the Stream data reference and its contentType.One can read,
+ * Create and update stream data by using this class.
+ *
+ *
+ * The {@link InputStream} to be read as Media Link Entry(MLE)/Stream from the
+ * server is fetched lazily using a call to the {@link #getInputStream(Service)}
+ * method. Please note that it is essential to pass the {@link Service} to the
+ * method as the service instance holds the authenticated credentials that needs
+ * to be passed as part of this client request.
+ *
+ *
+ * DO NOT use the {@link #getInputStream()} method for lazy fetching a
+ * stream; this method is used internally by the framework while saving the
+ * stream.When saving a MLE, please use the {@link #setInputStream(InputStream)}
+ * method to set the reference to the {@link InputStream} that you want to
+ * persist on the server.
+ *
+ *
+ * NOTE
+ *
+ * If you need to use blocking {@link InputStream} continous inputstream as
+ * in case of protocol buffers; please use the org.restlet.ext.net
+ * connector by placing the org.restlet.ext.net.jar file in the
+ * classpath.
+ * If you need to use non-blocking I/O to read the stream using buffered
+ * data reader as in the case you are reading files/documents; please use the
+ * org.restlet.ext.httpclient
connector by placing the
+ * org.restlet.ext.httpclient.jar file and it's dependencies in the
+ * classpath.
+ * Note that at any point of time the client can use only 1 connector and
+ * they have to be mutually exclusive.
+ *
+ */
+public class StreamReference extends Reference {
+
+ /** The input stream. */
+ private InputStream inputStream;
+
+ /** The content type. */
+ private String contentType;
+
+ /** isUpdateStreamData needs to be set to true for Stream Update */
+ private boolean isUpdateStreamData;
+
+ /**
+ * Instantiates a new stream reference. This method is used to create
+ * StreamReference with the URL.
+ *
+ * @param baseRef
+ * the base ref
+ * @param uriRef
+ * the uri ref
+ */
+ public StreamReference(Reference baseRef, String uriRef) {
+ super(baseRef, uriRef);
+ }
+
+ /**
+ * Instantiates a new stream reference. Use this to instantiates stream
+ * reference for doing create.
+ *
+ * @param contentType
+ * the content type
+ * @param inputStream
+ * the input stream
+ * @param isCreate
+ * the is create
+ */
+ public StreamReference(String contentType, InputStream inputStream) {
+ this.contentType = contentType;
+ this.inputStream = inputStream;
+ }
+
+ /**
+ * @return the contentType
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+ /**
+ * @param contentType
+ * the contentType to set
+ */
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ /**
+ * This method returns the stream that provides the handle to the data being
+ * pushed back from the server.
+ *
+ * The client program should use the org.restlet.ext.net connector
+ * when the client depends on the entire inputstream being available for
+ * processing say in case of processing Google Protocol Buffer streams.
+ *
+ *
+ * The client program should use the org.restlet.ext.httpclient
+ * connector when the client is downloading file or document based streams
+ * that don't need to be available for client program to process as
+ * continuous input stream.
+ *
+ * @param service
+ * the service
+ * @return the inputStream
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public InputStream getInputStream(Service service) throws IOException {
+
+ try {
+ ClientResource clientResource = service.createResource(this);
+ Representation representation = clientResource.get();
+ if (representation != null) {
+ // Provide a stream based on what is returned by the server
+ this.inputStream = representation.getStream();
+ }
+ } catch (IOException ioException) {
+ Context.getCurrentLogger().log(
+ Level.WARNING,
+ "Exception while retrieving the non blocking streaming data: "
+ + ioException.getMessage(), ioException);
+ throw ioException;
+ }
+ return this.inputStream;
+ }
+
+ /**
+ * @param inputStream
+ * the inputStream to set
+ */
+ public void setInputStream(InputStream inputStream) {
+ this.inputStream = inputStream;
+ }
+
+ /**
+ * Gets the input stream.
+ *
+ * @return the input stream
+ */
+ public InputStream getInputStream() {
+ return inputStream;
+ }
+
+ /**
+ * Checks if is update stream data.
+ *
+ * @return the isUpdateStreamData
+ */
+ public boolean isUpdateStreamData() {
+ return isUpdateStreamData;
+ }
+
+ /**
+ * Sets the update stream data.
+ *
+ * @param isUpdateStreamData
+ * the isUpdateStreamData to set
+ */
+ public void setUpdateStreamData(boolean isUpdateStreamData) {
+ this.isUpdateStreamData = isUpdateStreamData;
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/JavaReservedKeyWord.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/JavaReservedKeyWord.java
new file mode 100644
index 0000000000..a4a67f05fa
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/JavaReservedKeyWord.java
@@ -0,0 +1,21 @@
+
+package org.restlet.ext.odata.validation.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the annotated property is java reserved key word
+ *
+ * @author Akshay
+ */
+
+//Indicates that annotations with this type are to be retained by the VM so they can be read reflectively at run-time
+@Retention(RetentionPolicy.RUNTIME)
+//Indicates that this annotation type can be used to annotate only field
+@Target(ElementType.FIELD)
+public @interface JavaReservedKeyWord {
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/NotNull.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/NotNull.java
new file mode 100644
index 0000000000..e92757813e
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/NotNull.java
@@ -0,0 +1,21 @@
+
+package org.restlet.ext.odata.validation.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the annotated property can be null.
+ *
+ * @author Shantanu
+ */
+
+//Indicates that annotations with this type are to be retained by the VM so they can be read reflectively at run-time
+@Retention(RetentionPolicy.RUNTIME)
+//Indicates that this annotation type can be used to annotate only field
+@Target(ElementType.FIELD)
+public @interface NotNull {
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/PrimaryKey.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/PrimaryKey.java
new file mode 100644
index 0000000000..ef952e428b
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/PrimaryKey.java
@@ -0,0 +1,21 @@
+
+package org.restlet.ext.odata.validation.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the annotated property is Primary Key or not.
+ *
+ * @author Shantanu
+ */
+
+//Indicates that annotations with this type are to be retained by the VM so they can be read reflectively at run-time
+@Retention(RetentionPolicy.RUNTIME)
+//Indicates that this annotation type can be used to annotate only field
+@Target(ElementType.FIELD)
+public @interface PrimaryKey {
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/SystemGenerated.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/SystemGenerated.java
new file mode 100644
index 0000000000..779c4ce798
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/validation/annotation/SystemGenerated.java
@@ -0,0 +1,21 @@
+
+package org.restlet.ext.odata.validation.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the annotated property is System Generated or not.
+ *
+ * @author Shantanu
+ */
+
+//Indicates that annotations with this type are to be retained by the VM so they can be read reflectively at run-time
+@Retention(RetentionPolicy.RUNTIME)
+//Indicates that this annotation type can be used to annotate only field
+@Target(ElementType.FIELD)
+public @interface SystemGenerated {
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/xml/AtomFeedHandler.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/xml/AtomFeedHandler.java
new file mode 100644
index 0000000000..e76da1f806
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/xml/AtomFeedHandler.java
@@ -0,0 +1,874 @@
+package org.restlet.ext.odata.xml;
+
+import java.io.Reader;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.sql.Date;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.restlet.Context;
+import org.restlet.data.Language;
+import org.restlet.data.MediaType;
+import org.restlet.data.Reference;
+import org.restlet.ext.atom.Content;
+import org.restlet.ext.atom.Entry;
+import org.restlet.ext.atom.Feed;
+import org.restlet.ext.atom.Link;
+import org.restlet.ext.atom.Person;
+import org.restlet.ext.atom.Relation;
+import org.restlet.ext.odata.internal.edm.EntitySet;
+import org.restlet.ext.odata.internal.edm.EntityType;
+import org.restlet.ext.odata.internal.edm.Mapping;
+import org.restlet.ext.odata.internal.edm.Metadata;
+import org.restlet.ext.odata.internal.edm.TypeUtils;
+import org.restlet.ext.odata.internal.reflect.ReflectUtils;
+import org.restlet.ext.odata.streaming.StreamReference;
+import org.restlet.ext.xml.format.FormatParser;
+import org.restlet.ext.xml.format.XmlFormatParser;
+
+/**
+ * The Class AtomFeedHandler which parses the AtomFeed using STAX Event Iterator model.
+ *
+ * @param the generic type
+ *
+ * @author Onkar Dhuri
+ */
+public class AtomFeedHandler extends XmlFormatParser implements
+ FormatParser {
+
+ /** The metadata. */
+ protected Metadata metadata;
+
+ /** The entity set name. */
+ protected String entitySetName;
+
+ /** The entity type. */
+ private EntityType entityType;
+
+ /** The entity class. */
+ private Class> entityClass;
+
+ /** The entities. */
+ private List entities;
+
+ /** The references from the entry to Web resources. */
+ private volatile List links;
+
+ /** The feed. */
+ private Feed feed;
+
+ /** The baseURL. */
+ private String baseURL;
+
+ /**
+ * Gets the entities.
+ *
+ * @return the entities
+ */
+ public List getEntities() {
+ return entities;
+ }
+
+ /**
+ * Gets the feed.
+ *
+ * @return the feed
+ */
+ public Feed getFeed(){
+ if(feed == null){
+ feed = new Feed();
+ }
+ return feed;
+ }
+
+ /**
+ * Sets the feed.
+ *
+ * @param feed the new feed
+ */
+ public void setFeed(Feed feed){
+ this.feed = feed;
+ }
+
+ /**
+ * Returns the references from the entry to Web resources.
+ *
+ * @return The references from the entry to Web resources.
+ */
+ public List getLinks() {
+ // Lazy initialization with double-check.
+ List l = this.links;
+ if (l == null) {
+ synchronized (this) {
+ l = this.links;
+ if (l == null) {
+ this.links = l = new ArrayList ();
+ }
+ }
+ }
+ return l;
+ }
+
+ /**
+ * Instantiates a new atom feed handler.
+ *
+ * @param entitySetName the entity set name
+ * @param entityType the entity type
+ * @param entityClass the entity class
+ */
+ public AtomFeedHandler(String entitySetName, EntityType entityType, Class> entityClass) {
+ this.entitySetName = entitySetName;
+ this.entityType = entityType;
+ this.entityClass = entityClass;
+ this.entities = new ArrayList();
+ }
+
+ /**
+ * Instantiates a new atom feed handler.
+ *
+ * @param entitySetName the entity set name
+ * @param entityType the entity type
+ * @param entityClass the entity class
+ * @param metadata the metadata
+ */
+ public AtomFeedHandler(String entitySetName, EntityType entityType, Class> entityClass, Metadata metadata) {
+ this.entitySetName = entitySetName;
+ this.entityType = entityType;
+ this.entityClass = entityClass;
+ this.entities = new ArrayList();
+ this.metadata = metadata;
+ }
+
+ /* (non-Javadoc)
+ * @see org.restlet.ext.xml.format.FormatParser#parse(java.io.Reader)
+ */
+ public Feed parse(Reader reader) {
+ return parseFeed(reader, getEntitySet());
+ }
+
+ /**
+ * Parses the feed.
+ *
+ * @param reader the reader
+ * @param entitySet the entity set
+ * @return the feed
+ */
+ public Feed parseFeed(Reader reader, EntitySet entitySet) {
+ try {
+
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ XMLEventReader eventReader = factory.createXMLEventReader(reader);
+
+ while (eventReader.hasNext()) {
+ XMLEvent event;
+ event = eventReader.nextEvent();
+
+ if (isStartElement(event, ATOM_ENTRY)) {
+ @SuppressWarnings("unchecked")
+ // create instance of entity, parse it and add it to list of entities
+ T entity = (T) entityClass.newInstance();
+ this.parseEntry(eventReader, event.asStartElement(), entitySet, entity);
+ this.entities.add(entity);
+
+ } else if (isStartElement(event, ATOM_LINK)) {
+ if ("next".equals(event.asStartElement()
+ .getAttributeByName(new QName("rel")).getValue())) {
+ this.getFeed().setBaseReference(event.asStartElement()
+ .getAttributeByName(new QName("href"))
+ .getValue());
+ }
+ parseAtomFeedLinks(event);
+ } else if (isStartElement(event, ATOM_FEED)) {
+ Attribute attributeByName = event.asStartElement().getAttributeByName(XML_BASE);
+ if(attributeByName!=null){
+ baseURL=attributeByName.getValue();
+ }
+ } else if (isEndElement(event, ATOM_FEED)) {
+ // return from a sub feed, if we went down the hierarchy
+ break;
+ }
+
+ }
+ } catch (XMLStreamException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the feed due to: " + e.getMessage());
+ } catch (InstantiationException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the feed due to: " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the feed due to: " + e.getMessage());
+ }
+
+ return this.getFeed();
+
+ }
+
+ /**
+ * Method to parse atom links.
+ * @param event
+ */
+ private void parseAtomFeedLinks(XMLEvent event) {
+ Link link = new Link();
+ link.setHref(new Reference(event.asStartElement()
+ .getAttributeByName(new QName("href"))
+ .getValue()));
+ link.setRel(Relation.valueOf(event.asStartElement()
+ .getAttributeByName(new QName("rel"))
+ .getValue()));
+ if(null != event.asStartElement()
+ .getAttributeByName(new QName("type"))){
+ String type = event.asStartElement()
+ .getAttributeByName(new QName("type"))
+ .getValue();
+ if (type != null && type.length() > 0) {
+ link.setType(new MediaType(type));
+ }
+ }
+
+ if(null != event.asStartElement()
+ .getAttributeByName(new QName("hreflang"))){
+ link.setHrefLang(new Language(event.asStartElement()
+ .getAttributeByName(new QName("hreflang"))
+ .getValue()));
+ }
+
+ if(null != event.asStartElement()
+ .getAttributeByName(new QName("title"))){
+ link.setTitle(event.asStartElement()
+ .getAttributeByName(new QName("title"))
+ .getValue());
+ }
+
+ if(null != event.asStartElement()
+ .getAttributeByName(new QName("length"))){
+ final String attr = event.asStartElement()
+ .getAttributeByName(new QName("length"))
+ .getValue();
+ link.setLength((attr == null) ? -1L : Long.parseLong(attr));
+ }
+
+
+ // Glean the content
+ Content currentContent = new Content();
+ // Content available inline
+ //initiateInlineMixedContent();
+ link.setContent(currentContent);
+
+
+ getFeed().getLinks().add(link);
+ }
+
+
+
+ /**
+ * Parses all properties of an entity.
+ *
+ * @param the generic type
+ * @param reader the reader
+ * @param propertiesElement the properties element
+ * @param entity the entity
+ * @return the t
+ */
+ public static T parseProperties(
+ XMLEventReader reader, StartElement propertiesElement, T entity) {
+
+ try {
+ String propertyName = null;
+ while (reader.hasNext()) {
+ XMLEvent event = reader.nextEvent();
+
+ if (event.isEndElement()
+ && event.asEndElement().getName()
+ .equals(propertiesElement.getName())) {
+ return entity;
+ }
+
+ if (event.isStartElement()
+ && event.asStartElement().getName().getNamespaceURI()
+ .equals(NS_DATASERVICES)) {
+
+ String name = event.asStartElement().getName().getLocalPart();
+ propertyName = ReflectUtils.normalize(name);
+ //Check if that property is java reserved key word. If so then prefix it with '_'
+ if(ReflectUtils.isReservedWord(propertyName)){
+ propertyName="_"+propertyName;
+ }
+ parsePropertiesByType(reader, entity, propertyName, event);
+ }
+ }
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the properties due to: " + e.getMessage());
+ throw new RuntimeException();
+ }
+ return entity;
+ }
+
+ /** Method to parse properties of different types.
+ * @param reader
+ * @param entity
+ * @param propertyName
+ * @param event
+ * @throws XMLStreamException
+ * @throws Exception
+ */
+ @SuppressWarnings("unchecked")
+ private static void parsePropertiesByType(XMLEventReader reader, T entity, String propertyName, XMLEvent event) {
+ try {
+ Object value = null;
+ Attribute typeAttribute = event.asStartElement()
+ .getAttributeByName(M_TYPE);
+ Attribute nullAttribute = event.asStartElement()
+ .getAttributeByName(M_NULL);
+ boolean isNull = nullAttribute != null
+ && "true".equals(nullAttribute.getValue());
+ if (typeAttribute == null) { // Simple String
+ value = reader.getElementText();
+ } else if (typeAttribute.getValue().toLowerCase().startsWith("edm")
+ && !isNull) { // EDM Type
+ value = TypeUtils.fromEdm(reader.getElementText(),
+ typeAttribute.getValue());
+ } else if (typeAttribute.getValue().toLowerCase()
+ .startsWith("collection")) {// collection type
+ Object o = ReflectUtils.getPropertyObject(entity, propertyName);
+ // Delegate the collection handling to respective handler.
+ CollectionPropertyHandler.parse(reader, o,
+ event.asStartElement(), entity);
+ } else if (!isNull) {// complex type
+ // get or create the property instance
+ Object o = ReflectUtils.getPropertyObject(entity, propertyName);
+ // populate the object
+ parseProperties(reader, event.asStartElement(), (T) o);
+ // set it back to parent entity
+ ReflectUtils.invokeSetter(entity, propertyName, o);
+ }
+ if (value != null) {
+ ReflectUtils.invokeSetter(entity, propertyName, value);
+ }
+ } catch (XMLStreamException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the property due to: " + e.getMessage());
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the property due to: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Parses the ds atom entry.
+ *
+ * @param entityType the entity type
+ * @param reader the reader
+ * @param event the event
+ * @param entity the entity
+ */
+ private void parseDSAtomEntry(EntityType entityType, XMLEventReader reader, XMLEvent event, T entity) {
+ // as end element is not included in parseProperties, we need a wrapper method around it to handle it.
+ AtomFeedHandler.parseProperties(reader, event.asStartElement(), entity);
+ }
+
+
+ /**
+ * API will provide the Text for the given element
+ *
+ * @param reader - XMLEventReader
+ * @param element - StartElement
+ * @return String
+ */
+ public static String innerText(XMLEventReader reader, StartElement element) {
+ try {
+ StringWriter sw = new StringWriter();
+ while (reader.hasNext()) {
+
+ XMLEvent event = reader.nextEvent();
+ if (event.isEndElement()
+ && event.asEndElement().getName()
+ .equals(element.getName())) {
+
+ return sw.toString();
+ } else {
+ sw.append(event.asCharacters().getData());
+ }
+
+ }
+ } catch (XMLStreamException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the inner content due to: " + e.getMessage());
+ }
+ throw new RuntimeException();
+ }
+
+
+
+ /**
+ * Gets the entity set.
+ *
+ * @return the entity set
+ */
+ private EntitySet getEntitySet() {
+ EntitySet entitySet = new EntitySet(entitySetName);
+ entitySet.setType(entityType);
+
+ return entitySet;
+ }
+
+ /**
+ * Parses the entry.
+ *
+ * @param reader the reader
+ * @param entryElement the entry element
+ * @param entitySet the entity set
+ * @param entity the entity
+ * @return the t
+ */
+ @SuppressWarnings("rawtypes")
+ private T parseEntry(XMLEventReader reader,
+ StartElement entryElement, EntitySet entitySet, T entity) {
+
+ String id = null;
+ String title = null;
+ String summary = null;
+ String updated = null;
+ String contentType = null;
+ Person p = null;
+ String relativeURL=null;
+ //read the base URL form Feed/Entry
+ if(null==baseURL){
+ Attribute attributeByName = entryElement.getAttributeByName(XML_BASE);
+ if(attributeByName!=null){
+ baseURL=attributeByName.getValue();
+ }
+ }
+
+
+ Entry rt = new Entry();
+
+ while (reader.hasNext()) {
+ try {
+ XMLEvent event;
+ event = reader.nextEvent();
+ if (event.isEndElement()
+ && event.asEndElement().getName()
+ .equals(entryElement.getName())) {
+ rt.setId(id); // http://localhost:8810/Oneoff01.svc/Comment(1)
+ rt.setTitle(title);
+ rt.setSummary(summary);
+ rt.setUpdated(Date.valueOf(updated.split("T")[0]));
+ this.getFeed().getEntries().add(rt);
+ if(p!=null){
+ //set author details in the entity.
+ setDetailsOfPerson(entity, p, null); // third parameter would be null if we don't have contributor object.
+ }
+ return entity;
+ }
+
+ if (isStartElement(event, ATOM_ID)) {
+ id = reader.getElementText();
+ } else if (isStartElement(event, ATOM_TITLE)) {
+ title = reader.getElementText();
+ } else if (isStartElement(event, ATOM_SUMMARY)) {
+ summary = reader.getElementText();
+ } else if (isStartElement(event, ATOM_UPDATED)) {
+ updated = reader.getElementText();
+ } else if (isStartElement(event, ATOM_LINK)) {
+ Link link = parseAtomLink(reader, event.asStartElement(),
+ entitySet, entity);
+ rt.getLinks().add(link);
+ } else if (isStartElement(event, M_PROPERTIES)) {
+ parseDSAtomEntry(entitySet.getType(), reader, event, entity);
+ /*} else if (isStartElement(event, M_ACTION)) {
+ AtomFunction function = parseAtomFunction(reader,
+ event.asStartElement());
+ actions.put(function.getFQFunctionName(), metadata
+ .findFunctionImport(function.title,
+ entitySet.getType(), FunctionKind.Action));
+ } else if (isStartElement(event, M_FUNCTION)) {
+ AtomFunction function = parseAtomFunction(reader,
+ event.asStartElement());
+ functions.put(function.getFQFunctionName(), metadata
+ .findFunctionImport(function.title,
+ entitySet.getType(), FunctionKind.Function));*/
+ } else if(isStartElement(event, ATOM_AUTHOR)){
+ // handle Author tag completely and create person object.
+ p = new Person();
+ parseAuthor(reader, p, event);
+ } else if (isStartElement(event, ATOM_CONTENT)) {
+ contentType = getAttributeValueIfExists(event.asStartElement(),
+ "type");
+ relativeURL = getAttributeValueIfExists(event.asStartElement(),
+ "src");
+ if (MediaType.APPLICATION_XML.getName().equals(contentType)) {
+ StartElement contentElement = event.asStartElement();
+ StartElement valueElement = null;
+ while (reader.hasNext()) {
+ // handle content in separate handlers
+ XMLEvent event2;
+ try {
+ event2 = reader.nextEvent();
+ if (valueElement == null && event2.isStartElement()) {
+ valueElement = event2.asStartElement();
+ if (isStartElement(event2, M_PROPERTIES)) {
+ this.parseDSAtomEntry(entitySet.getType(), reader, event2, entity);
+ } else {
+ // TODO: Onkar : Set Basic content by implementing innerText method later
+ //BasicAtomEntry bae = new BasicAtomEntry();
+ Entry bae = new Entry();
+ //bae.content = innerText(reader, event2.asStartElement());
+ rt = bae;
+ }
+ }
+ if (event2.isEndElement()
+ && event2.asEndElement().getName()
+ .equals(contentElement.getName())) {
+ break;
+ }
+ } catch (XMLStreamException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the entry due to: " + e.getMessage());
+ }
+ }
+ } else {
+ if(entityType.isBlob()){
+ for (Field field : entity.getClass()
+ .getDeclaredFields()) {
+ Class> type = field.getType();
+ if(type.getName().contains("StreamReference")){
+ Reference baseReference = new Reference(baseURL);
+ StreamReference streamReference = new StreamReference(baseReference,relativeURL);
+ streamReference.setContentType(contentType);
+ ReflectUtils.invokeSetter(entity,
+ ReflectUtils.normalize(field.getName()), streamReference);
+ break;
+ }
+ }
+ }
+ Entry e = new Entry();
+ // TODO: Onkar : Set Basic content by implementing innerText method later
+ //e.setContent(innerText(reader, event.asStartElement()));
+ rt = e;
+ }
+ } else if(event.toString() != null && event.toString().isEmpty() && event.toString().trim().isEmpty()){
+ continue;
+ } else { // Handle Custom feeds where some properties are outside content tag. ie. not in m:properties
+ if(event.isStartElement()){
+ List mappings = metadata.getMappings();
+ Entry e = new Entry();
+ StartElement element = event.asStartElement();
+ String parentTag = element.getName().getLocalPart();
+
+ // Iterate through inline attributes and set respective property for the entity.
+ // Eg:
+ String nsPrefix = element.getName().getPrefix();
+ for (Iterator iterator1 = element.getAttributes(); iterator1.hasNext();) {
+ Attribute attribute = (Attribute)iterator1.next();
+ String attributeValue = getAttributeValueIfExists(element, attribute.getName());
+ String attibuteTag = parentTag+"/@"+attribute.getName().getLocalPart();
+ for (Iterator iterator = mappings.iterator(); iterator.hasNext();) {
+ Mapping mapping = (Mapping) iterator.next();
+ if(null != mapping.getNsPrefix() && mapping.getNsPrefix().equalsIgnoreCase(nsPrefix)){
+ if(attributeValue!= null & mapping.getValuePath().equalsIgnoreCase(attibuteTag)){
+ String propertyName = ReflectUtils.normalize(mapping.getPropertyPath());
+ ReflectUtils.invokeSetter(entity, propertyName, attributeValue);
+ break;
+ }
+ }
+ }
+ }
+
+
+ StartElement valueElement = null;
+ String propertyName = null;
+ while(reader.hasNext()){
+
+ XMLEvent event2;
+
+ try {
+ // iterate all the sub-elements under parent tag with
+ event2 = reader.nextEvent();
+ if (event2.isEndElement()
+ && event2.asEndElement().getName()
+ .equals(element.getName())) {
+ break;
+ }
+ if (valueElement == null && event2.isStartElement()) {
+ valueElement = event2.asStartElement();
+ // Iterate through sub-paths and set respective property for the entity.
+ // Eg:Cafe corp.
+ String innerTag = parentTag+"/"+valueElement.getName().getLocalPart();
+ for (Iterator iterator = mappings.iterator(); iterator.hasNext();) {
+ Mapping mapping = (Mapping) iterator.next();
+ if(mapping.getValuePath().equalsIgnoreCase(innerTag)){
+
+ //TODO: Abhijeet : Extract this into method and refer it in parseProperties
+ propertyName = ReflectUtils.normalize(mapping.getPropertyPath());
+ parsePropertiesByType(reader, entity, propertyName, event2);
+ break; // exit for loop if mapping is present and addressed
+
+ }
+ }
+ }
+ }catch (XMLStreamException e1) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the entry due to: " + e1.getMessage());
+ } catch (Exception e1) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the entry due to: " + e1.getMessage());
+ }
+ }
+ rt = e;
+ }
+ }
+ } catch (XMLStreamException e1) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the entry due to: " + e1.getMessage());
+ } catch (Exception e1) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the entry due to: " + e1.getMessage());
+ }
+
+ }
+ throw new RuntimeException();
+ }
+
+ /**
+ * @param reader
+ * @param p
+ * @param event
+ */
+ private void parseAuthor(XMLEventReader reader, Person p, XMLEvent event) {
+ StartElement contentElement = event.asStartElement();
+ StartElement valueElement = null;
+ while (reader.hasNext()) {
+ // handle content in separate handlers
+ XMLEvent event2;
+ try {
+ event2 = reader.nextEvent();
+ if (valueElement == null && event2.isStartElement()) {
+ valueElement = event2.asStartElement();
+ if (isStartElement(event2, ATOM_NAME)) {
+ String name = reader.getElementText();
+ if(!name.isEmpty()){
+ p.setName(name);
+ }
+ }else if (isStartElement(event2, ATOM_EMAIL)) {
+ String email = reader.getElementText();
+ if(!email.isEmpty()){
+ p.setEmail(email);
+ }
+ }
+ }
+ if (event2.isEndElement()
+ && event2.asEndElement().getName()
+ .equals(contentElement.getName())) {
+ break;
+ }
+ }catch (XMLStreamException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the author due to: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Method to set atom mappings to corresponding entity.
+ * @param entity
+ * @param author
+ * @param contributor
+ */
+ private void setDetailsOfPerson(T entity, Person author, Person contributor) {
+ // Handle Atom mapped values.
+ for (Mapping m : metadata.getMappings()) {
+ if (entityType != null && entityType.equals(m.getType())
+ && m.getNsUri() == null && m.getNsPrefix() == null) {
+
+ Object value = null;
+ if ("SyndicationAuthorEmail".equals(m.getValuePath())) {
+ value = (author != null) ? author.getEmail() : null;
+ } else if ("SyndicationAuthorName".equals(m.getValuePath())) {
+ value = (author != null) ? author.getName() : null;
+ } else if ("SyndicationAuthorUri".equals(m.getValuePath())) {
+ value = (author != null) ? author.getUri().toString()
+ : null;
+ } else if ("SyndicationContributorEmail".equals(m
+ .getValuePath())) {
+ value = (contributor != null) ? contributor.getEmail()
+ : null;
+ } else if ("SyndicationContributorName"
+ .equals(m.getValuePath())) {
+ value = (contributor != null) ? contributor.getName()
+ : null;
+ } else if ("SyndicationContributorUri".equals(m.getValuePath())) {
+ value = (contributor != null) ? contributor.getUri()
+ .toString() : null;
+ } /*else if ("SyndicationPublished".equals(m.getValuePath())) {
+ value = entry.getPublished();
+ } else if ("SyndicationRights".equals(m.getValuePath())) {
+ value = (entry.getRights() != null) ? entry.getRights()
+ .getContent() : null;
+ } else if ("SyndicationSummary".equals(m.getValuePath())) {
+ value = entry.getSummary();
+ } else if ("SyndicationTitle".equals(m.getValuePath())) {
+ value = (entry.getTitle() != null) ? entry.getTitle()
+ .getContent() : null;
+ } else if ("SyndicationUpdated".equals(m.getValuePath())) {
+ value = entry.getUpdated();
+ }*/
+
+ try {
+ if (value != null) {
+ ReflectUtils.invokeSetter(entity, m.getPropertyPath(),
+ value);
+ }
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the content due to: " + e.getMessage());
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Parses the atom link.
+ *
+ * @param reader the reader
+ * @param linkElement the link element
+ * @param entitySet the entity set
+ * @param entity the entity
+ * @return the link
+ */
+ private Link parseAtomLink(XMLEventReader reader, StartElement linkElement,
+ EntitySet entitySet, T entity) {
+
+ try {
+ Link rt = new Link();
+ rt.setRel(Relation.valueOf(getAttributeValueIfExists(linkElement,
+ "rel")));
+ rt.setType(MediaType.valueOf(getAttributeValueIfExists(linkElement,
+ "type")));
+ rt.setTitle(getAttributeValueIfExists(linkElement, "title"));
+ rt.setHref(new Reference(getAttributeValueIfExists(linkElement,
+ "href")));
+ //boolean inlineContent = false;
+
+ // expected cases:
+ // 1. - no inlined content, i.e. deferred
+ // 2. - inlined content but null entity or empty feed
+ // 3. ... - inlined content with 1 or more items
+ // 4. .. - inlined content 1 an item
+
+ while (reader.hasNext()) {
+ XMLEvent event;
+ event = reader.nextEvent();
+
+ if (event.isEndElement()
+ && event.asEndElement().getName()
+ .equals(linkElement.getName())) {
+ break;
+ } else if (isStartElement(event, XmlFormatParser.M_INLINE)) {
+ //inlineContent = true; // may be null content.
+ } else if (isStartElement(event, ATOM_FEED)) {
+ //skip all tags until we encounter first entry element to exclude link and other tags.
+ // Fix for edit link tag to prevent pre-matured exit of parent link iteration.
+ while( reader.hasNext()){
+ event = reader.nextEvent();
+ if(isStartElement(event,ATOM_ENTRY)){
+ String propertyName = rt.getHref().getLastSegment();
+ // create a property object
+ Object o = ReflectUtils.getPropertyObject(entity, propertyName);
+ parseInlineEntities(reader, entitySet, entity, event, propertyName, o);
+ // This break is added to not handle additional inline entities here. Those entries shall be handled in next else-if block.
+ break;
+ } else if(event.isEndElement() && event.asEndElement().getName().equals(ATOM_FEED.getLocalPart())){
+ break;
+ }
+ }
+ } else if (isStartElement(event, ATOM_ENTRY)) { //handle the inline entity
+ String propertyName = rt.getHref().getLastSegment();
+ // create a property object
+ Object o = ReflectUtils.getPropertyObject(entity, propertyName);
+ parseInlineEntities(reader, entitySet, entity, event, propertyName, o);
+ }
+ }
+ return rt;
+ } catch (XMLStreamException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the atom link due to: " + e.getMessage());
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the atom link due to: " + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * Method to parse Inline entities.
+ * @param reader
+ * @param entitySet
+ * @param entity
+ * @param event
+ * @param propertyName
+ * @param o
+ * @throws NoSuchFieldException
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ * @throws Exception
+ */
+ @SuppressWarnings(value = {"unchecked", "rawtypes" })
+ private void parseInlineEntities(XMLEventReader reader, EntitySet entitySet, T entity, XMLEvent event,
+ String propertyName, Object o) {
+ try {
+ if (o instanceof List) { // Collection of complex i.e. one to many association
+ Field field = entity.getClass().getDeclaredField(ReflectUtils.normalize(propertyName));
+ // String currentMType = startElement.getAttributeByName(M_TYPE).getValue();
+ // get the parameterize type using reflection
+ if (field.getGenericType() instanceof ParameterizedType) {
+ // determine what type of collection it is
+ ParameterizedType listType = (ParameterizedType) field.getGenericType();
+ Class> listClass = (Class>) listType.getActualTypeArguments()[0];
+ // Create new Item Instance
+ Object obj;
+ obj = listClass.newInstance();
+
+ // create a new instance and populate the properties
+ this.parseEntry(reader, event.asStartElement(), entitySet, (T) obj);
+ ((List) o).add(obj);
+ }
+
+ } else { // complex object i.e. embedded object in parent entity
+ // populate the object
+ this.parseEntry(reader, event.asStartElement(), entitySet, (T) o);
+ // set it back to parent entity
+ ReflectUtils.invokeSetter(entity, ReflectUtils.normalize(propertyName), o);
+ }
+ } catch (InstantiationException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the inline entities due to: " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the inline entities due to: " + e.getMessage());
+ } catch (SecurityException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the inline entities due to: " + e.getMessage());
+ } catch (NoSuchFieldException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the inline entities due to: " + e.getMessage());
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the inline entities due to: " + e.getMessage());
+ }
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/xml/CollectionPropertyHandler.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/xml/CollectionPropertyHandler.java
new file mode 100644
index 0000000000..a19c3df813
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/xml/CollectionPropertyHandler.java
@@ -0,0 +1,105 @@
+package org.restlet.ext.odata.xml;
+
+import static org.restlet.ext.xml.format.XmlFormatParser.DATASERVICES_ELEMENT;
+import static org.restlet.ext.xml.format.XmlFormatParser.M_TYPE;
+import static org.restlet.ext.xml.format.XmlFormatParser.NS_DATASERVICES;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.util.List;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.restlet.Context;
+import org.restlet.ext.odata.internal.edm.TypeUtils;
+
+/**
+ * The Class CollectionPropertyHandler which handles all type of collections.
+ *
+ * @author Onkar Dhuri
+ */
+public class CollectionPropertyHandler {
+
+ /**
+ * Parses the collection of either simple type or complex type
+ *
+ * @param the generic type
+ * @param reader the reader
+ * @param entity the entity
+ * @param startElement the start element
+ * @param parentEntity the parent entity
+ * @return the t
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public static T parse(XMLEventReader reader, T entity,
+ StartElement startElement, T parentEntity) {
+
+ try {
+ Object obj = null;
+ String collectionType;
+ while (reader.hasNext()) {
+ XMLEvent event = reader.nextEvent();
+
+ if (event.isEndElement()
+ && event.asEndElement().getName()
+ .equals(startElement.getName())) {
+ return entity;
+ }
+
+ if (event.isStartElement()
+ && event.asStartElement().getName().getNamespaceURI()
+ .equals(NS_DATASERVICES)
+ && event.asStartElement().getName()
+ .equals(DATASERVICES_ELEMENT)) {
+ if (entity instanceof List) { // check first if it is type of List
+ Field field = parentEntity.getClass().getDeclaredField(
+ startElement.getName().getLocalPart());
+ String currentMType = startElement.getAttributeByName(
+ M_TYPE).getValue();
+ if (field.getGenericType() instanceof ParameterizedType) {
+ // determine what type of collection it is
+ ParameterizedType listType = (ParameterizedType) field
+ .getGenericType();
+ collectionType = TypeUtils
+ .getCollectionType(currentMType);
+ Class> listClass = (Class>) listType
+ .getActualTypeArguments()[0];
+ if (collectionType.toLowerCase().startsWith("edm")) { // simple type
+ // just add value to list
+ Object value = TypeUtils.convert(listClass,
+ reader.getElementText());
+ ((List) entity).add(value);
+ } else { // complex type
+ obj = listClass.newInstance();
+ // create a new instance and populate the properties
+ AtomFeedHandler.parseProperties(reader,
+ event.asStartElement(), obj);
+ ((List) entity).add(obj);
+ }
+ }
+ }
+ }
+ }
+ } catch (XMLStreamException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the collection due to: " + e.getMessage());
+ } catch (SecurityException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the collection due to: " + e.getMessage());
+ } catch (NoSuchFieldException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the collection due to: " + e.getMessage());
+ } catch (InstantiationException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the collection due to: " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ Context.getCurrentLogger().warning(
+ "Cannot parse the collection due to: " + e.getMessage());
+ }
+ return entity;
+ }
+
+}
diff --git a/modules/org.restlet.ext.xml/module.xml b/modules/org.restlet.ext.xml/module.xml
index 42fe1a3041..b5ecbc2a79 100644
--- a/modules/org.restlet.ext.xml/module.xml
+++ b/modules/org.restlet.ext.xml/module.xml
@@ -9,6 +9,7 @@
+
diff --git a/modules/org.restlet.ext.xml/src/org/restlet/ext/xml/format/FormatParser.java b/modules/org.restlet.ext.xml/src/org/restlet/ext/xml/format/FormatParser.java
new file mode 100644
index 0000000000..586b30cf4a
--- /dev/null
+++ b/modules/org.restlet.ext.xml/src/org/restlet/ext/xml/format/FormatParser.java
@@ -0,0 +1,28 @@
+package org.restlet.ext.xml.format;
+
+import java.io.Reader;
+
+/**
+ * Deals with parsing the resulting stream into a Entry
or
+ * Feed
and converting it to a OEntity
. The
+ * implementation depends on the format Atom or Json.
+ *
+ * @param Atom or json
+ *
+ * @author Onkar Dhuri
+ *
+ * @see Entry
+ * @see Feed
+ * @see OEntity
+ */
+public interface FormatParser {
+
+ /**
+ * Parses the feed from reader
+ *
+ * @param reader the reader
+ * @return the t
+ */
+ T parse(Reader reader);
+
+}
diff --git a/modules/org.restlet.ext.xml/src/org/restlet/ext/xml/format/XmlFormatParser.java b/modules/org.restlet.ext.xml/src/org/restlet/ext/xml/format/XmlFormatParser.java
new file mode 100644
index 0000000000..61ca232479
--- /dev/null
+++ b/modules/org.restlet.ext.xml/src/org/restlet/ext/xml/format/XmlFormatParser.java
@@ -0,0 +1,252 @@
+package org.restlet.ext.xml.format;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.core4j.Enumerable;
+
+/**
+ * The Class XmlFormatParser.
+ *
+ * @author Onkar Dhuri
+ */
+public class XmlFormatParser {
+
+ public static final String NS_APP = "http://www.w3.org/2007/app";
+ public static final String NS_XML = "http://www.w3.org/XML/1998/namespace";
+ public static final String NS_ATOM = "http://www.w3.org/2005/Atom";
+
+ public static final String NS_METADATA = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
+ public static final String NS_DATASERVICES = "http://schemas.microsoft.com/ado/2007/08/dataservices";
+ public static final String NS_SCHEME = "http://schemas.microsoft.com/ado/2007/08/dataservices/scheme";
+ public static final String NS_RELATED = "http://schemas.microsoft.com/ado/2007/08/dataservices/related/";
+ public static final String NS_EDM2006 = "http://schemas.microsoft.com/ado/2006/04/edm"; // edm 1.0
+ public static final String NS_EDM2007 = "http://schemas.microsoft.com/ado/2007/05/edm"; // edm 1.1
+ public static final String NS_EDM2008_1 = "http://schemas.microsoft.com/ado/2008/01/edm"; // edm 1.2
+ public static final String NS_EDM2008_9 = "http://schemas.microsoft.com/ado/2008/09/edm"; // edm 2.0
+ public static final String NS_EDM2009_8 = "http://schemas.microsoft.com/ado/2009/08/edm"; // edm ???
+ public static final String NS_EDM2009_11 = "http://schemas.microsoft.com/ado/2009/11/edm"; // edm 3.0
+ public static final String NS_EDMX = "http://schemas.microsoft.com/ado/2007/06/edmx";
+ public static final String NS_EDMANNOTATION = "http://schemas.microsoft.com/ado/2009/02/edm/annotation";
+ public static final String NS_CUSTOM_EDMANNOTATION = "http://www.lgc.com/dsdataserver/annotation";
+
+ public static final QName EDMX_EDMX = new QName(NS_EDMX, "Edmx");
+ public static final QName EDMX_DATASERVICES = new QName(NS_EDMX, "DataServices");
+
+ public static final QName EDM2006_SCHEMA = new QName(NS_EDM2006, "Schema");
+ public static final QName EDM2006_ENTITYTYPE = new QName(NS_EDM2006, "EntityType");
+ public static final QName EDM2006_ASSOCIATION = new QName(NS_EDM2006, "Association");
+ public static final QName EDM2006_COMPLEXTYPE = new QName(NS_EDM2006, "ComplexType");
+ public static final QName EDM2006_ENTITYCONTAINER = new QName(NS_EDM2006, "EntityContainer");
+ public static final QName EDM2006_ENTITYSET = new QName(NS_EDM2006, "EntitySet");
+ public static final QName EDM2006_ASSOCIATIONSET = new QName(NS_EDM2006, "AssociationSet");
+ public static final QName EDM2006_FUNCTIONIMPORT = new QName(NS_EDM2006, "FunctionImport");
+ public static final QName EDM2006_PARAMETER = new QName(NS_EDM2006, "Parameter");
+ public static final QName EDM2006_END = new QName(NS_EDM2006, "End");
+ public static final QName EDM2006_ONDELETE = new QName(NS_EDM2006, "OnDelete");
+ public static final QName EDM2006_REFCONSTRAINT = new QName(NS_EDM2006, "ReferentialConstraint");
+ public static final QName EDM2006_PRINCIPAL = new QName(NS_EDM2006, "Principal");
+ public static final QName EDM2006_DEPENDENT = new QName(NS_EDM2006, "Dependent");
+ public static final QName EDM2006_PROPERTYREF = new QName(NS_EDM2006, "PropertyRef");
+ public static final QName EDM2006_PROPERTY = new QName(NS_EDM2006, "Property");
+ public static final QName EDM2006_NAVIGATIONPROPERTY = new QName(NS_EDM2006, "NavigationProperty");
+
+ public static final QName EDM2007_SCHEMA = new QName(NS_EDM2007, "Schema");
+ public static final QName EDM2007_ENTITYTYPE = new QName(NS_EDM2007, "EntityType");
+ public static final QName EDM2007_ASSOCIATION = new QName(NS_EDM2007, "Association");
+ public static final QName EDM2007_COMPLEXTYPE = new QName(NS_EDM2007, "ComplexType");
+ public static final QName EDM2007_ENTITYCONTAINER = new QName(NS_EDM2007, "EntityContainer");
+ public static final QName EDM2007_ENTITYSET = new QName(NS_EDM2007, "EntitySet");
+ public static final QName EDM2007_ASSOCIATIONSET = new QName(NS_EDM2007, "AssociationSet");
+ public static final QName EDM2007_FUNCTIONIMPORT = new QName(NS_EDM2007, "FunctionImport");
+ public static final QName EDM2007_PARAMETER = new QName(NS_EDM2007, "Parameter");
+ public static final QName EDM2007_END = new QName(NS_EDM2007, "End");
+ public static final QName EDM2007_ONDELETE = new QName(NS_EDM2007, "OnDelete");
+ public static final QName EDM2007_REFCONSTRAINT = new QName(NS_EDM2007, "ReferentialConstraint");
+ public static final QName EDM2007_PRINCIPAL = new QName(NS_EDM2007, "Principal");
+ public static final QName EDM2007_DEPENDENT = new QName(NS_EDM2007, "Dependent");
+ public static final QName EDM2007_PROPERTYREF = new QName(NS_EDM2007, "PropertyRef");
+ public static final QName EDM2007_PROPERTY = new QName(NS_EDM2007, "Property");
+ public static final QName EDM2007_NAVIGATIONPROPERTY = new QName(NS_EDM2007, "NavigationProperty");
+
+ public static final QName EDM2008_1_SCHEMA = new QName(NS_EDM2008_1, "Schema");
+ public static final QName EDM2008_1_ENTITYTYPE = new QName(NS_EDM2008_1, "EntityType");
+ public static final QName EDM2008_1_ASSOCIATION = new QName(NS_EDM2008_1, "Association");
+ public static final QName EDM2008_1_COMPLEXTYPE = new QName(NS_EDM2008_1, "ComplexType");
+ public static final QName EDM2008_1_ENTITYCONTAINER = new QName(NS_EDM2008_1, "EntityContainer");
+ public static final QName EDM2008_1_ENTITYSET = new QName(NS_EDM2008_1, "EntitySet");
+ public static final QName EDM2008_1_ASSOCIATIONSET = new QName(NS_EDM2008_1, "AssociationSet");
+ public static final QName EDM2008_1_FUNCTIONIMPORT = new QName(NS_EDM2008_1, "FunctionImport");
+ public static final QName EDM2008_1_PARAMETER = new QName(NS_EDM2008_1, "Parameter");
+ public static final QName EDM2008_1_END = new QName(NS_EDM2008_1, "End");
+ public static final QName EDM2008_1_ONDELETE = new QName(NS_EDM2008_1, "OnDelete");
+ public static final QName EDM2008_1_REFCONSTRAINT = new QName(NS_EDM2008_1, "ReferentialConstraint");
+ public static final QName EDM2008_1_PRINCIPAL = new QName(NS_EDM2008_1, "Principal");
+ public static final QName EDM2008_1_DEPENDENT = new QName(NS_EDM2008_1, "Dependent");
+ public static final QName EDM2008_1_PROPERTYREF = new QName(NS_EDM2008_1, "PropertyRef");
+ public static final QName EDM2008_1_PROPERTY = new QName(NS_EDM2008_1, "Property");
+ public static final QName EDM2008_1_NAVIGATIONPROPERTY = new QName(NS_EDM2008_1, "NavigationProperty");
+
+ public static final QName EDM2008_9_SCHEMA = new QName(NS_EDM2008_9, "Schema");
+ public static final QName EDM2008_9_ENTITYTYPE = new QName(NS_EDM2008_9, "EntityType");
+ public static final QName EDM2008_9_ASSOCIATION = new QName(NS_EDM2008_9, "Association");
+ public static final QName EDM2008_9_COMPLEXTYPE = new QName(NS_EDM2008_9, "ComplexType");
+ public static final QName EDM2008_9_ENTITYCONTAINER = new QName(NS_EDM2008_9, "EntityContainer");
+ public static final QName EDM2008_9_ENTITYSET = new QName(NS_EDM2008_9, "EntitySet");
+ public static final QName EDM2008_9_ASSOCIATIONSET = new QName(NS_EDM2008_9, "AssociationSet");
+ public static final QName EDM2008_9_FUNCTIONIMPORT = new QName(NS_EDM2008_9, "FunctionImport");
+ public static final QName EDM2008_9_PARAMETER = new QName(NS_EDM2008_9, "Parameter");
+ public static final QName EDM2008_9_END = new QName(NS_EDM2008_9, "End");
+ public static final QName EDM2008_9_ONDELETE = new QName(NS_EDM2008_9, "OnDelete");
+ public static final QName EDM2008_9_REFCONSTRAINT = new QName(NS_EDM2008_9, "ReferentialConstraint");
+ public static final QName EDM2008_9_PRINCIPAL = new QName(NS_EDM2008_9, "Principal");
+ public static final QName EDM2008_9_DEPENDENT = new QName(NS_EDM2008_9, "Dependent");
+ public static final QName EDM2008_9_PROPERTYREF = new QName(NS_EDM2008_9, "PropertyRef");
+ public static final QName EDM2008_9_PROPERTY = new QName(NS_EDM2008_9, "Property");
+ public static final QName EDM2008_9_NAVIGATIONPROPERTY = new QName(NS_EDM2008_9, "NavigationProperty");
+
+ public static final QName EDM2009_8_SCHEMA = new QName(NS_EDM2009_8, "Schema");
+ public static final QName EDM2009_8_ENTITYTYPE = new QName(NS_EDM2009_8, "EntityType");
+ public static final QName EDM2009_8_ASSOCIATION = new QName(NS_EDM2009_8, "Association");
+ public static final QName EDM2009_8_COMPLEXTYPE = new QName(NS_EDM2009_8, "ComplexType");
+ public static final QName EDM2009_8_ENTITYCONTAINER = new QName(NS_EDM2009_8, "EntityContainer");
+ public static final QName EDM2009_8_ENTITYSET = new QName(NS_EDM2009_8, "EntitySet");
+ public static final QName EDM2009_8_ASSOCIATIONSET = new QName(NS_EDM2009_8, "AssociationSet");
+ public static final QName EDM2009_8_FUNCTIONIMPORT = new QName(NS_EDM2009_8, "FunctionImport");
+ public static final QName EDM2009_8_PARAMETER = new QName(NS_EDM2009_8, "Parameter");
+ public static final QName EDM2009_8_END = new QName(NS_EDM2009_8, "End");
+ public static final QName EDM2009_8_ONDELETE = new QName(NS_EDM2009_8, "OnDelete");
+ public static final QName EDM2009_8_REFCONSTRAINT = new QName(NS_EDM2009_8, "ReferentialConstraint");
+ public static final QName EDM2009_8_PRINCIPAL = new QName(NS_EDM2009_8, "Principal");
+ public static final QName EDM2009_8_DEPENDENT = new QName(NS_EDM2009_8, "Dependent");
+ public static final QName EDM2009_8_PROPERTYREF = new QName(NS_EDM2009_8, "PropertyRef");
+ public static final QName EDM2009_8_PROPERTY = new QName(NS_EDM2009_8, "Property");
+ public static final QName EDM2009_8_NAVIGATIONPROPERTY = new QName(NS_EDM2009_8, "NavigationProperty");
+
+ public static final QName EDM2009_11_SCHEMA = new QName(NS_EDM2009_11, "Schema");
+ public static final QName EDM2009_11_ENTITYTYPE = new QName(NS_EDM2009_11, "EntityType");
+ public static final QName EDM2009_11_ASSOCIATION = new QName(NS_EDM2009_11, "Association");
+ public static final QName EDM2009_11_COMPLEXTYPE = new QName(NS_EDM2009_11, "ComplexType");
+ public static final QName EDM2009_11_ENTITYCONTAINER = new QName(NS_EDM2009_11, "EntityContainer");
+ public static final QName EDM2009_11_ENTITYSET = new QName(NS_EDM2009_11, "EntitySet");
+ public static final QName EDM2009_11_ASSOCIATIONSET = new QName(NS_EDM2009_11, "AssociationSet");
+ public static final QName EDM2009_11_FUNCTIONIMPORT = new QName(NS_EDM2009_11, "FunctionImport");
+ public static final QName EDM2009_11_PARAMETER = new QName(NS_EDM2009_11, "Parameter");
+ public static final QName EDM2009_11_END = new QName(NS_EDM2009_11, "End");
+ public static final QName EDM2009_11_ONDELETE = new QName(NS_EDM2009_11, "OnDelete");
+ public static final QName EDM2009_11_REFCONSTRAINT = new QName(NS_EDM2009_11, "ReferentialConstraint");
+ public static final QName EDM2009_11_PRINCIPAL = new QName(NS_EDM2009_11, "Principal");
+ public static final QName EDM2009_11_DEPENDENT = new QName(NS_EDM2009_11, "Dependent");
+ public static final QName EDM2009_11_PROPERTYREF = new QName(NS_EDM2009_11, "PropertyRef");
+ public static final QName EDM2009_11_PROPERTY = new QName(NS_EDM2009_11, "Property");
+ public static final QName EDM2009_11_NAVIGATIONPROPERTY = new QName(NS_EDM2009_11, "NavigationProperty");
+
+ public static final QName ATOM_FEED = new QName(NS_ATOM, "feed");
+ public static final QName ATOM_ENTRY = new QName(NS_ATOM, "entry");
+ public static final QName ATOM_ID = new QName(NS_ATOM, "id");
+ public static final QName ATOM_TITLE = new QName(NS_ATOM, "title");
+ public static final QName ATOM_SUMMARY = new QName(NS_ATOM, "summary");
+ public static final QName ATOM_UPDATED = new QName(NS_ATOM, "updated");
+ public static final QName ATOM_CATEGORY = new QName(NS_ATOM, "category");
+ public static final QName ATOM_CONTENT = new QName(NS_ATOM, "content");
+ public static final QName ATOM_LINK = new QName(NS_ATOM, "link");
+ public static final QName ATOM_AUTHOR = new QName(NS_ATOM, "author");
+ public static final QName ATOM_NAME = new QName(NS_ATOM, "name");
+ public static final QName ATOM_EMAIL = new QName(NS_ATOM, "email");
+
+ public static final QName APP_WORKSPACE = new QName(NS_APP, "workspace");
+ public static final QName APP_SERVICE = new QName(NS_APP, "service");
+ public static final QName APP_COLLECTION = new QName(NS_APP, "collection");
+ public static final QName APP_ACCEPT = new QName(NS_APP, "accept");
+
+ public static final QName M_ETAG = new QName(NS_METADATA, "etag");
+ public static final QName M_PROPERTIES = new QName(NS_METADATA, "properties");
+ public static final QName M_ACTION = new QName(NS_METADATA, "action");
+ public static final QName M_FUNCTION = new QName(NS_METADATA, "function");
+ public static final QName M_TYPE = new QName(NS_METADATA, "type");
+ public static final QName M_NULL = new QName(NS_METADATA, "null");
+ public static final QName M_INLINE = new QName(NS_METADATA, "inline");
+ public static final QName M_MIMETYPE = new QName(NS_METADATA, "MimeType");
+ public static final QName M_FC_TARGETPATH = new QName(NS_METADATA, "FC_TargetPath");
+ public static final QName M_FC_CONTENTKIND = new QName(NS_METADATA, "FC_ContentKind");
+ public static final QName M_FC_KEEPINCONTENT = new QName(NS_METADATA, "FC_KeepInContent");
+ public static final QName M_FC_EPMCONTENTKIND = new QName(NS_METADATA, "FC_EpmContentKind");
+ public static final QName M_FC_EPMKEEPINCONTENT = new QName(NS_METADATA, "FC_EpmKeepInContent");
+ public static final QName M_FC_NSPREFIX = new QName(NS_METADATA, "FC_NsPrefix");
+ public static final QName M_FC_NSURI = new QName(NS_METADATA, "FC_NsUri");
+
+ public static final QName DATASERVICES_ELEMENT = new QName(NS_DATASERVICES, "element"); // a collection element
+
+ public static final QName XML_BASE = new QName(NS_XML, "base");
+
+ protected static boolean isStartElement(XMLEvent event, QName... names) {
+ if (!event.isStartElement()) {
+ return false;
+ }
+ QName name = new QName(event.asStartElement().getName().getNamespaceURI(), event.asStartElement().getName().getLocalPart());
+ return Enumerable.create(names).contains(name);
+
+ }
+
+ protected static boolean isElement(XMLEvent event, QName... names) {
+ QName name = new QName(event.asStartElement().getName().getNamespaceURI(), event.asStartElement().getName().getLocalPart());
+ return Enumerable.create(names).contains(name);
+
+ }
+
+ protected static boolean isEndElement(XMLEvent event, QName qname) {
+ if (!event.isEndElement()) {
+ return false;
+ }
+ QName name = event.asEndElement().getName();
+ return name.getNamespaceURI().equals(qname.getNamespaceURI())
+ && name.getLocalPart().equals(qname.getLocalPart());
+ }
+
+ protected static String urlCombine(String base, String rel) {
+ if (!base.endsWith("/") && !rel.startsWith("/"))
+ base = base + "/";
+ return base + rel;
+ }
+
+ protected static String getAttributeValueIfExists(StartElement element, String localName) {
+ return getAttributeValueIfExists(element, new QName(null, localName));
+ }
+
+ protected static String getAttributeValueIfExists(StartElement element, QName attName) {
+ Attribute rt = element.getAttributeByName(attName);
+ return rt == null ? null : rt.getValue();
+ }
+
+ protected static boolean isStartElement(XMLStreamReader reader, QName... names) {
+ if (!reader.isStartElement()) {
+ return false;
+ }
+ QName name = new QName(reader.getNamespaceURI(), reader.getLocalName());
+ return Enumerable.create(names).contains(name);
+
+ }
+
+ protected static boolean isElement(XMLStreamReader reader, QName... names) {
+ QName name = new QName(reader.getNamespaceURI(), reader.getLocalName());
+ return Enumerable.create(names).contains(name);
+
+ }
+
+ protected static boolean isEndElement(XMLStreamReader reader, QName qname) {
+ if (!reader.isEndElement()) {
+ return false;
+ }
+ QName name = new QName(reader.getNamespaceURI(), reader.getLocalName());
+ return name.getNamespaceURI().equals(qname.getNamespaceURI())
+ && name.getLocalPart().equals(qname.getLocalPart());
+ }
+
+ protected static String getAttributeValueIfExists(XMLStreamReader reader, String attName) {
+ return reader.getAttributeValue(null, attName);
+ }
+
+}
diff --git a/modules/org.restlet.test/module.xml b/modules/org.restlet.test/module.xml
index c5c4001d89..22078f2f5d 100644
--- a/modules/org.restlet.test/module.xml
+++ b/modules/org.restlet.test/module.xml
@@ -12,6 +12,7 @@
+
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/Cafe.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/Cafe.java
new file mode 100644
index 0000000000..4b746a8097
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/Cafe.java
@@ -0,0 +1,119 @@
+package org.restlet.test.batch.crud;
+
+/**
+ * Generated by the generator tool for the RestletBatch service extension for
+ * the Restlet framework.
+ *
+ * @see Metadata of the
+ * target Restlet Data Services
+ *
+ */
+public class Cafe {
+
+ /** The city. */
+ private String city;
+
+ /** The id. */
+ private String id;
+
+ /** The name. */
+ private String name;
+
+ /** The zip code. */
+ private int zipCode;
+
+ /**
+ * Constructor without parameter.
+ *
+ */
+ public Cafe() {
+ super();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id
+ * The identifiant value of the entity.
+ */
+ public Cafe(String id) {
+ this();
+ this.id = id;
+ }
+
+ /**
+ * Returns the value of the city attribute.
+ *
+ * @return The value of the city attribute.
+ */
+ public String getCity() {
+ return city;
+ }
+
+ /**
+ * Returns the value of the id attribute.
+ *
+ * @return The value of the id attribute.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Returns the value of the name attribute.
+ *
+ * @return The value of the name attribute.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of the zipCode attribute.
+ *
+ * @return The value of the zipCode attribute.
+ */
+ public int getZipCode() {
+ return zipCode;
+ }
+
+ /**
+ * Sets the value of the city attribute.
+ *
+ * @param city
+ * the new city
+ */
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ /**
+ * Sets the value of the id attribute.
+ *
+ * @param id
+ * the new id
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Sets the value of the name attribute.
+ *
+ * @param name
+ * the new name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the value of the zipCode attribute.
+ *
+ * @param zipCode
+ * the new zip code
+ */
+ public void setZipCode(int zipCode) {
+ this.zipCode = zipCode;
+ }
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/CafeCrudApplication.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CafeCrudApplication.java
new file mode 100644
index 0000000000..c882210dac
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CafeCrudApplication.java
@@ -0,0 +1,346 @@
+package org.restlet.test.batch.crud;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.jvnet.mimepull.Header;
+import org.jvnet.mimepull.MIMEMessage;
+import org.jvnet.mimepull.MIMEPart;
+import org.restlet.Application;
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.Restlet;
+import org.restlet.data.CharacterSet;
+import org.restlet.data.LocalReference;
+import org.restlet.data.MediaType;
+import org.restlet.data.Method;
+import org.restlet.data.Parameter;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.ext.odata.batch.util.BatchConstants;
+import org.restlet.ext.odata.batch.util.BodyPart;
+import org.restlet.ext.odata.batch.util.Multipart;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.routing.Router;
+import org.restlet.util.Series;
+
+/**
+ * Sample application that simulates the CUD operation on entities.
+ */
+
+public class CafeCrudApplication extends Application {
+
+ /**
+ * The Class dataLogger.
+ */
+ private static class BatchTestRestlet extends Restlet {
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER1 = Logger
+ .getLogger(CreateCafeTestCase.class.getName());
+
+ /** The batch id added to response. */
+ private static boolean batchIdAddedToResponse = false;
+
+ /** The builder. */
+ private static StringBuilder builder = new StringBuilder();
+
+ /** The batch id. */
+ private static String batchId = null;
+
+ /** The batch xmlFilePath. */
+ private static final String xmlFilePath = "/org/restlet/test/batch/xml/";
+
+ /** The file. */
+ String fileName;
+
+ /**
+ * Instantiates a new data logger.
+ *
+ * @param context
+ * the context
+ * @param file
+ * the file
+ * @param updatable
+ * the updatable
+ */
+ public BatchTestRestlet(Context context, String xmlFileName,
+ boolean updatable) {
+ super(context);
+ this.fileName = xmlFileName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.Restlet#handle(org.restlet.Request,
+ * org.restlet.Response)
+ */
+ @Override
+ public void handle(Request request, Response response) {
+
+ if (Method.GET.equals(request.getMethod())) {
+ String filePath = xmlFilePath;
+ Response r = getContext().getClientDispatcher().handle(
+ new Request(Method.GET, LocalReference
+ .createClapReference(LocalReference.CLAP_CLASS,
+ filePath + fileName + ".xml")));
+ response.setEntity(r.getEntity());
+ response.setStatus(r.getStatus());
+
+ } else if (Method.POST.equals(request.getMethod())) {
+ String rep = null;
+ try {
+ rep = request.getEntity().getText();
+ String[] split = rep.split("\r\n");
+ for (int i = 0; i < split.length; i++) {
+ createResponse(split[i], builder);
+ }
+ response.setEntity(new StringRepresentation(builder
+ .toString()));
+ setResponse(response, Status.SUCCESS_OK);
+ } catch (IOException e) {
+ response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+ }
+ if (null != rep && !rep.isEmpty()) {
+ response.setStatus(Status.SUCCESS_OK);
+ }
+
+ }
+ }
+
+ /**
+ * Creates the response as per the method type.
+ *
+ * @param rep
+ * the rep
+ * @param sb
+ * the sb
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ private void createResponse(String rep, StringBuilder sb)
+ throws IOException {
+ String filePath = null;
+ if (rep.contains(Method.GET.toString())) {
+ LOGGER1.info("This is Get method");
+ filePath = getFilePath("getCafeResponse.xml");
+ readResponseAndFillBuffer(sb, filePath);
+
+ } else if (rep.contains(Method.DELETE.toString())) {
+ LOGGER1.info("This is delete method");
+ filePath = getFilePath("deleteCafeResponse.xml");
+ readResponseAndFillBuffer(sb, filePath);
+
+ } else if (rep.contains(Method.PUT.toString())) {
+ LOGGER1.info("This is put method");
+ filePath = getFilePath("updateCafeResponse.xml");
+ readResponseAndFillBuffer(sb, filePath);
+
+ } else if (rep.contains(Method.POST.toString())) {
+ LOGGER1.info("This is post method");
+ filePath = getFilePath("createCafeResponse.xml");
+ readResponseAndFillBuffer(sb, filePath);
+ } else if (rep.contains("--changeset")) {
+
+ sb.append("\n\n").append(
+ rep.replace("changeset", "changesetresponse"));
+
+ } else if (rep.contains("--batch")) {
+ if (!batchIdAddedToResponse) {
+ filePath = getFilePath("parentBatchResponse.xml");
+ String replace = rep.replace("batch", "batchresponse");
+ if (replace.contains("batch")) {
+ String[] split = replace.split("_");
+ batchId = split[1];
+ }
+ readResponseAndFillBuffer(sb, filePath);
+ String str = sb.toString();
+ str = str
+ .replace(
+ "batchresponse_1f82a90b-43f1-4276-b20a-59da3437dfa8",
+ "batchresponse_" + batchId);
+ String timeStamp = new SimpleDateFormat(
+ "yyyy:MM:dd_HH:mm:ss").format(Calendar
+ .getInstance().getTime());
+ str = str.replace("Date: Mon, 23 June 2014 09:44:08 GMT",
+ "Date:" + timeStamp);
+ builder = new StringBuilder(str);
+ batchIdAddedToResponse = true;
+ }
+ builder.append("\n\n").append(
+ rep.replace("batch", "batchresponse"));
+
+ } else if (rep
+ .contains("Content-Type: application/atom+xml;charset=utf-8")) {
+
+ sb.append("\n\n")
+ .append(rep
+ .replace(
+ "Content-Type: application/atom+xml;charset=utf-8",
+ ""));
+
+ } else if (rep.contains("Content-Type")) {
+ if (rep.contains("changeset")) {
+ sb.append("\n").append(
+ rep.replace("changeset", "changesetresponse"));
+ } else {
+ sb.append("\n").append(
+ rep.replace("Content-Type", "Content-Type"));
+ }
+ } else if (rep.contains("changeset_")) {
+ sb.append("\n").append(
+ rep.replace("changeset_", "changesetresponse_"));
+ } else if (rep.contains("Content-Transfer-Encoding:")) {
+ sb.append("\n").append(
+ rep.replace("Content-Transfer-Encoding",
+ "Content-Transfer-Encoding"));
+ }
+
+ }
+
+ /**
+ * Gets the complete xml filePath
+ *
+ * @param fileName
+ * the file name
+ * @return the file path
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ private String getFilePath(String fileName) throws IOException {
+ return new File(".").getCanonicalPath() + "/src" + xmlFilePath
+ + fileName;
+ }
+
+ /**
+ * Read response and fill buffer.
+ *
+ * @param sb
+ * the sb
+ * @param filePath
+ * the file path
+ * @throws FileNotFoundException
+ * the file not found exception
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ private void readResponseAndFillBuffer(StringBuilder sb, String filePath)
+ throws FileNotFoundException, IOException {
+ InputStream is = new FileInputStream(new File(filePath));
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader br = new BufferedReader(isr);
+ while (br.ready()) {
+ sb.append(br.readLine()).append("\n");
+
+ }
+ br.close();
+ }
+
+ /**
+ * Sets the response.
+ *
+ * @param response
+ * the response
+ * @param status
+ * the status
+ */
+ private void setResponse(Response response, Status status) {
+ Series parameters = new Series(
+ Parameter.class);
+ parameters.add("boundary", "batchresponse_" + batchId);
+ MediaType mediaType = new MediaType(
+ MediaType.MULTIPART_MIXED.toString(), parameters);
+ response.getEntity().setMediaType(mediaType);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.Application#createInboundRoot()
+ */
+ @Override
+ public Restlet createInboundRoot() {
+ getMetadataService().setDefaultCharacterSet(CharacterSet.ISO_8859_1);
+ getConnectorService().getClientProtocols().add(Protocol.CLAP);
+ Router router = new Router(getContext());
+
+ router.attach("/$metadata", new BatchTestRestlet(getContext(),
+ "metadata", true));
+ router.attach("/Cafes", new BatchTestRestlet(getContext(), "cafes",
+ true));
+ router.attach("/Cafes('40')", new BatchTestRestlet(getContext(),
+ "cafesUpdatedRequest", true));
+ router.attach("/$batch", new BatchTestRestlet(getContext(), "cafes",
+ true));
+
+ return router;
+ }
+
+ /**
+ * Creates the multipart.
+ *
+ * A Multipart is a logical representation of a batch request or Chnagset.
+ * It is a set of multiple http requests/response.
+ *
+ * @param is
+ * the is
+ * @param mediaType
+ * the media type
+ * @return the multipart
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public static Multipart createMultipart(InputStream is, MediaType mediaType)
+ throws IOException {
+ // create a multipart
+ Multipart multipart = new Multipart();
+ // set its mediatype
+ multipart.setMediaType(mediaType);
+
+ MIMEMessage mimeMessage = new MIMEMessage(is, mediaType.getParameters()
+ .getFirstValue(BatchConstants.BATCH_BOUNDARY));
+ List attachments = mimeMessage.getAttachments();
+ for (MIMEPart mimePart : attachments) {
+ BodyPart bodyPart = new BodyPart(mimePart);
+ // copy headers into bodyparts
+ copyHeaders(bodyPart, mimePart);
+ bodyPart.setMediaType(new MediaType(bodyPart.getHeaders().getFirst(
+ BatchConstants.HTTP_HEADER_CONTENT_TYPE)));
+ multipart.addBodyParts(bodyPart);
+
+ }
+ return multipart;
+ }
+
+ /**
+ * Copy headers.
+ *
+ * @param bodyPart
+ * the body part
+ * @param mimePart
+ * the mime part
+ */
+ private static void copyHeaders(BodyPart bodyPart, MIMEPart mimePart) {
+ MultivaluedMap bpHeaders = bodyPart.getHeaders();
+ List extends Header> mHeaders = mimePart.getAllHeaders();
+ for (Header header : mHeaders) {
+ bpHeaders.add(header.getName(), header.getValue());
+ }
+
+ }
+
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/CafeService.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CafeService.java
new file mode 100644
index 0000000000..9133e0af10
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CafeService.java
@@ -0,0 +1,98 @@
+package org.restlet.test.batch.crud;
+
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.Service;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.BatchRequestImpl;
+import org.restlet.ext.odata.batch.request.impl.CreateEntityRequest;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * Generated by the generator tool for the RestletBatch service extension for
+ * the Restlet framework.
+ *
+ * @see Metadata of the
+ * target RestletBatch service
+ *
+ *
+ */
+public class CafeService extends Service {
+
+ /**
+ * Constructor.
+ *
+ */
+ public CafeService() {
+ super("http://localhost:8111/Cafe.svc/");
+ }
+
+ /**
+ * Adds a new entity to the service.
+ *
+ * @param entity
+ * The entity to add to the service.
+ * @return the creates the entity request
+ * @throws Exception
+ * the exception
+ */
+ public CreateEntityRequest addEntity(Cafe entity) throws Exception {
+ return addEntity("/Cafes", entity);
+ }
+
+ /**
+ * Creates a query for cafe entities hosted by this service.
+ *
+ * @param subpath
+ * The path to this entity relatively to the service URI.
+ * @return A query object.
+ */
+ public Query createCafeQuery(String subpath) {
+ return createQuery(subpath, Cafe.class);
+ }
+
+ /**
+ * Updates a query for cafe entities hosted by this service.
+ *
+ * @param subpath
+ * The path to this entity relatively to the service URI.
+ * @return A query object.
+ */
+
+ public Query updateCafeQuery(String subpath) {
+ return createQuery(subpath, Cafe.class);
+ }
+
+ /**
+ * Deletes a query for cafe entities hosted by this service.
+ *
+ * @param subpath
+ * The path to this entity relatively to the service URI.
+ * @return A query object.
+ */
+
+ public Query deleteCafeQuery(String subpath) {
+ return createQuery(subpath, Cafe.class);
+ }
+
+ /**
+ * Gets a query for cafe entities hosted by this service.
+ *
+ * @param subpath
+ * The path to this entity relatively to the service URI.
+ * @return A query object.
+ */
+
+ public Query getCafeQuery(String subpath) {
+ return createQuery(subpath, Cafe.class);
+ }
+
+ /**
+ * Method to perform batch operations. It maintains the list of
+ * clientBatchRequests within a batch.
+ *
+ * @return list of request in batch.
+ */
+ public BatchRequest createBatchRequest() {
+ return new BatchRequestImpl(this);
+ }
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/CreateCafeTestCase.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CreateCafeTestCase.java
new file mode 100644
index 0000000000..a5f342f0ed
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CreateCafeTestCase.java
@@ -0,0 +1,154 @@
+package org.restlet.test.batch.crud;
+
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.ChangeSetRequestImpl;
+import org.restlet.ext.odata.batch.request.impl.CreateEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * Test case for RestletBatch service for CREATE operation on entities.
+ *
+ */
+public class CreateCafeTestCase extends RestletTestCase {
+
+ /** The Constant cafeName. */
+ private static final String cafeName = "TestName";
+
+ /** The Constant cafeId. */
+ private static final String cafeId = "40";
+
+ /** The Constant cafeZipCode. */
+ private static final int cafeZipCode = 111111;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger
+ .getLogger(CreateCafeTestCase.class.getName());
+
+ /** The Constant cafeCity. */
+ private static final String cafeCity = "TestCity";
+
+ /** Inner component. */
+ private Component component = new Component();
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test method for CREATE operation on simple entities.
+ */
+ public void testCreate() {
+ CafeService service = new CafeService();
+
+ // create.
+ Cafe cafe = new Cafe();
+ cafe.setId(cafeId);
+ cafe.setName(cafeName);
+ cafe.setCity(cafeCity);
+ cafe.setZipCode(cafeZipCode);
+ try {
+
+ BatchRequest br = service.createBatchRequest();
+ ChangeSetRequestImpl changeSetRequest = new ChangeSetRequestImpl();
+ // Create request
+ CreateEntityRequest createEntityRequest = new CreateEntityRequest(
+ service, cafe);
+ changeSetRequest.addRequest(createEntityRequest);
+ List responses = br.addRequest(changeSetRequest)
+ .execute();
+ dumpResponse(responses);
+ // Assert for response.
+ Query createquery = service.createCafeQuery("/Cafes");
+ Cafe cafe1 = createquery.iterator().next();
+ assertEquals(cafeName, cafe1.getName());
+ assertEquals(cafeId, cafe1.getId());
+ assertEquals(cafeZipCode, cafe1.getZipCode());
+ Response latestResponse = createquery.getService()
+ .getLatestResponse();
+ latestResponse = createquery.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK, latestResponse.getStatus());
+ } catch (Exception ex) {
+ LOGGER.log(Level.SEVERE, ex.getMessage());
+ Assert.fail();
+ }
+ }
+
+ /**
+ * Dump response.
+ *
+ * @param responses
+ * the responses
+ */
+ @SuppressWarnings("unchecked")
+ public static void dumpResponse(List responses) {
+ for (BatchResponse batchResponse : responses) {
+ Object entity = batchResponse.getEntity();
+ if (batchResponse instanceof ChangeSetResponse) {
+ LOGGER.info("Dumping changeset");
+ dumpResponse((List) entity);
+ LOGGER.info("Done with changeset");
+ } else {
+ LOGGER.info("Status =" + batchResponse.getStatus());
+ LOGGER.info("Entity = " + entity);
+ MultivaluedMap headers = batchResponse
+ .getHeaders();
+ if (headers != null) {
+ Set keySet = headers.keySet();
+ LOGGER.info("Headers : ");
+ for (String key : keySet) {
+ List value = headers.get(key);
+ LOGGER.info("Key =" + key + "/t" + "value = " + value);
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/CreateDeleteChangeSetTestCase.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CreateDeleteChangeSetTestCase.java
new file mode 100644
index 0000000000..e16e2e44a6
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CreateDeleteChangeSetTestCase.java
@@ -0,0 +1,166 @@
+package org.restlet.test.batch.crud;
+
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.ChangeSetRequestImpl;
+import org.restlet.ext.odata.batch.request.impl.CreateEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.DeleteEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * Test case for RestletBatch service for CREATE & DELETE operation on entities.
+ *
+ */
+public class CreateDeleteChangeSetTestCase extends RestletTestCase {
+
+ /** The Constant cafeName. */
+ private static final String cafeName = "TestName";
+
+ /** The Constant cafeId. */
+ private static final String cafeId = "40";
+
+ /** The Constant cafeZipCode. */
+ private static final int cafeZipCode = 111111;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger
+ .getLogger(CreateDeleteChangeSetTestCase.class.getName());
+
+ /** The Constant cafeCity. */
+ private static final String cafeCity = "TestCity";
+
+ /** Inner component. */
+ private Component component = new Component();
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test method for CREATE & DELETE operation on simple entities.
+ */
+ public void testCreateDelete() {
+ CafeService service = new CafeService();
+
+ // create & delete
+ Cafe cafe = new Cafe();
+ cafe.setId(cafeId);
+ cafe.setName(cafeName);
+ cafe.setCity(cafeCity);
+ cafe.setZipCode(cafeZipCode);
+
+ try {
+
+ BatchRequest br = service.createBatchRequest();
+ ChangeSetRequestImpl changeSetRequest = new ChangeSetRequestImpl();
+ // Create request
+ CreateEntityRequest createEntityRequest = new CreateEntityRequest(
+ service, cafe);
+ DeleteEntityRequest deleteEntityRequest = new DeleteEntityRequest(
+ service, cafe);
+ changeSetRequest.addRequest(createEntityRequest);
+ changeSetRequest.addRequest(deleteEntityRequest);
+ List responses = br.addRequest(changeSetRequest)
+ .execute();
+ for (BatchResponse batchResponse : responses) {
+ batchResponse.getEntity();
+ dumpResponse(responses);
+ }
+
+ // Assert for response.
+ Query createquery = service.createCafeQuery("/Cafes");
+ Cafe cafe1 = createquery.iterator().next();
+ assertEquals(cafeName, cafe1.getName());
+ assertEquals(cafeId, cafe1.getId());
+ assertEquals(cafeZipCode, cafe1.getZipCode());
+ Response latestResponse = createquery.getService()
+ .getLatestResponse();
+ latestResponse = createquery.getService().getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ Query deletequery = service.deleteCafeQuery(("/Cafes('40')"));
+ latestResponse = deletequery.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK, latestResponse.getStatus());
+ } catch (Exception ex) {
+ LOGGER.log(Level.SEVERE, ex.getMessage());
+ Assert.fail();
+ }
+ }
+
+ /**
+ * Dump response.
+ *
+ * @param responses
+ * the responses
+ */
+ @SuppressWarnings("unchecked")
+ public static void dumpResponse(List responses) {
+ for (BatchResponse batchResponse : responses) {
+ Object entity = batchResponse.getEntity();
+ if (batchResponse instanceof ChangeSetResponse) {
+ LOGGER.info("Dumping changeset");
+ dumpResponse((List) entity);
+ LOGGER.info("Done with changeset");
+ } else {
+ LOGGER.info("Status =" + batchResponse.getStatus());
+ LOGGER.info("Entity = " + entity);
+ MultivaluedMap headers = batchResponse
+ .getHeaders();
+ if (headers != null) {
+ Set keySet = headers.keySet();
+ LOGGER.info("Headers : ");
+ for (String key : keySet) {
+ List value = headers.get(key);
+ LOGGER.info("Key =" + key + "/t" + "value = " + value);
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/CreateUpdateChangeSetTestCase.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CreateUpdateChangeSetTestCase.java
new file mode 100644
index 0000000000..5b47eaa34c
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/CreateUpdateChangeSetTestCase.java
@@ -0,0 +1,172 @@
+package org.restlet.test.batch.crud;
+
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.ChangeSetRequestImpl;
+import org.restlet.ext.odata.batch.request.impl.CreateEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.UpdateEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * Test case for RestletBatch service for CREATE & UPDATE operation on entities.
+ *
+ */
+public class CreateUpdateChangeSetTestCase extends RestletTestCase {
+
+ /** The Constant cafeName. */
+ private static final String cafeName = "TestName";
+
+ /** The Constant cafeId. */
+ private static final String cafeId = "40";
+
+ /** The Constant cafeZipCode. */
+ private static final int cafeZipCode = 111111;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger
+ .getLogger(CreateUpdateChangeSetTestCase.class.getName());
+
+ /** The Constant cafeCity. */
+ private static final String cafeCity = "TestCity";
+
+ /** The Constant cafeNameUpdated. */
+ private static final String cafeNameUpdated = "TestName-updated";
+
+ /** Inner component. */
+ private Component component = new Component();
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test method for CREATE & UPDATE operation on simple entities.
+ */
+ public void testCreateUpdate() {
+ CafeService service = new CafeService();
+
+ // create.
+ Cafe cafe = new Cafe();
+ cafe.setId(cafeId);
+ cafe.setName(cafeName);
+ cafe.setCity(cafeCity);
+ cafe.setZipCode(cafeZipCode);
+
+ // update
+ Cafe cafeU = new Cafe();
+ cafe.setName(cafeNameUpdated);
+ try {
+
+ BatchRequest br = service.createBatchRequest();
+ ChangeSetRequestImpl changeSetRequest = new ChangeSetRequestImpl();
+ // Create request
+ CreateEntityRequest createEntityRequest = new CreateEntityRequest(
+ service, cafe);
+ UpdateEntityRequest updateEntityRequest = new UpdateEntityRequest(
+ service, cafeU);
+ changeSetRequest.addRequest(createEntityRequest);
+ changeSetRequest.addRequest(updateEntityRequest);
+ List responses = br.addRequest(changeSetRequest)
+ .execute();
+ for (BatchResponse batchResponse : responses) {
+ batchResponse.getEntity();
+ dumpResponse(responses);
+ }
+
+ // Assert for response.
+ Query createquery = service.createCafeQuery("/Cafes");
+ Cafe cafe1 = createquery.iterator().next();
+ assertEquals(cafeName, cafe1.getName());
+ assertEquals(cafeId, cafe1.getId());
+ assertEquals(cafeZipCode, cafe1.getZipCode());
+ Response latestResponse = createquery.getService()
+ .getLatestResponse();
+ latestResponse = createquery.getService().getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ Query updatequery = service.updateCafeQuery("/Cafes('40')");
+ latestResponse = updatequery.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK, latestResponse.getStatus());
+ } catch (Exception ex) {
+ LOGGER.log(Level.SEVERE, ex.getMessage());
+ Assert.fail();
+ }
+ }
+
+ /**
+ * Dump response.
+ *
+ * @param responses
+ * the responses
+ */
+ @SuppressWarnings("unchecked")
+ public static void dumpResponse(List responses) {
+ for (BatchResponse batchResponse : responses) {
+ Object entity = batchResponse.getEntity();
+ if (batchResponse instanceof ChangeSetResponse) {
+ LOGGER.info("Dumping changeset");
+ dumpResponse((List) entity);
+ LOGGER.info("Done with changeset");
+ } else {
+ LOGGER.info("Status =" + batchResponse.getStatus());
+ LOGGER.info("Entity = " + entity);
+ MultivaluedMap headers = batchResponse
+ .getHeaders();
+ if (headers != null) {
+ Set keySet = headers.keySet();
+ LOGGER.info("Headers : ");
+ for (String key : keySet) {
+ List value = headers.get(key);
+ LOGGER.info("Key =" + key + "/t" + "value = " + value);
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/DeleteCafeTestCase.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/DeleteCafeTestCase.java
new file mode 100644
index 0000000000..1418192eb3
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/DeleteCafeTestCase.java
@@ -0,0 +1,152 @@
+package org.restlet.test.batch.crud;
+
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.ChangeSetRequestImpl;
+import org.restlet.ext.odata.batch.request.impl.DeleteEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * Test case for RestletBatch service for DELETE operation on entities.
+ */
+public class DeleteCafeTestCase extends RestletTestCase {
+
+ /** The Constant cafeName. */
+ private static final String cafeName = "TestName";
+
+ /** The Constant cafeId. */
+ private static final String cafeId = "40";
+
+ /** The Constant cafeZipCode. */
+ private static final int cafeZipCode = 111111;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger
+ .getLogger(DeleteCafeTestCase.class.getName());
+
+ /** The Constant cafeCity. */
+ private static final String cafeCity = "TestCity";
+
+ /** Inner component. */
+ private Component component = new Component();
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test method for DELETE operation on simple entities.
+ */
+ public void testDelete() {
+ CafeService service = new CafeService();
+
+ // create.
+ Cafe cafe = new Cafe();
+ cafe.setId(cafeId);
+ cafe.setName(cafeName);
+ cafe.setCity(cafeCity);
+ cafe.setZipCode(cafeZipCode);
+
+ // delete
+ Cafe cafeD = new Cafe();
+ cafeD.setId(cafeId);
+ cafeD.setName(cafeName);
+ cafeD.setCity("TestCity");
+ cafeD.setZipCode(cafeZipCode);
+ try {
+ BatchRequest br = service.createBatchRequest();
+ ChangeSetRequestImpl changeSetRequest = new ChangeSetRequestImpl();
+ // Create request
+ DeleteEntityRequest deleteEntityRequest = new DeleteEntityRequest(
+ service, cafe);
+ changeSetRequest.addRequest(deleteEntityRequest);
+ List responses = br.addRequest(changeSetRequest)
+ .execute();
+ dumpResponse(responses);
+ Query deleteQuery = service.deleteCafeQuery("/Cafes('40')");
+ Response latestResponse = deleteQuery.getService()
+ .getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ } catch (Exception ex) {
+ LOGGER.log(Level.SEVERE, ex.getMessage());
+ Assert.fail();
+ }
+ }
+
+ /**
+ * Dump response.
+ *
+ * @param responses
+ * the responses
+ */
+ @SuppressWarnings("unchecked")
+ public static void dumpResponse(List responses) {
+ for (BatchResponse batchResponse : responses) {
+ Object entity = batchResponse.getEntity();
+ if (batchResponse instanceof ChangeSetResponse) {
+ LOGGER.info("Dumping changeset");
+ dumpResponse((List) entity);
+ LOGGER.info("Done with changeset");
+ } else {
+ LOGGER.info("Status =" + batchResponse.getStatus());
+ LOGGER.info("Entity = " + entity);
+ MultivaluedMap headers = batchResponse
+ .getHeaders();
+ if (headers != null) {
+ Set keySet = headers.keySet();
+ LOGGER.info("Headers : ");
+ for (String key : keySet) {
+ List value = headers.get(key);
+ LOGGER.info("Key =" + key + "/t" + "value = " + value);
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/GetCafeTestCase.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/GetCafeTestCase.java
new file mode 100644
index 0000000000..3c635715f9
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/GetCafeTestCase.java
@@ -0,0 +1,149 @@
+package org.restlet.test.batch.crud;
+
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.GetEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * Test case for RestletBatch service for GET operation on entities.
+ */
+public class GetCafeTestCase extends RestletTestCase {
+
+ /** The Constant cafeName. */
+ private static final String cafeName = "TestName";
+
+ /** The Constant cafeId. */
+ private static final String cafeId = "40";
+
+ /** The Constant cafeZipCode. */
+ private static final int cafeZipCode = 111111;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger.getLogger(GetCafeTestCase.class
+ .getName());
+
+ /** The Constant cafeCity. */
+ private static final String cafeCity = "TestCity";
+
+ /** Inner component. */
+ private Component component = new Component();
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test method for GET operation on simple entities.
+ */
+ public void testGet() {
+
+ // Get
+ CafeService service = new CafeService();
+ Cafe cafeG = new Cafe();
+ cafeG.setId(cafeId);
+ cafeG.setName(cafeName);
+ cafeG.setCity(cafeCity);
+ cafeG.setZipCode(cafeZipCode);
+ try {
+ BatchRequest br = service.createBatchRequest();
+ // get request
+ Query getQuery = service.createQuery("/Cafes('40')",
+ Cafe.class);
+ GetEntityRequest getEntityRequest = new GetEntityRequest(getQuery);
+ List responses = br.addRequest(getEntityRequest)
+ .execute();
+ dumpResponse(responses);
+ Assert.assertTrue(true);
+ // Assert for response.
+ Query getquery = service.getCafeQuery("/Cafes");
+ Cafe cafe2 = getquery.iterator().next();
+ assertEquals(cafeName, cafe2.getName());
+ assertEquals(cafeId, cafe2.getId());
+ assertEquals(cafeZipCode, cafe2.getZipCode());
+ Response latestResponse = getQuery.getService().getLatestResponse();
+ latestResponse = getquery.getService().getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ } catch (Exception ex) {
+ LOGGER.log(Level.SEVERE, ex.getMessage());
+ Assert.fail();
+ }
+ }
+
+ /**
+ * Dump response.
+ *
+ * @param responses
+ * the responses
+ */
+ @SuppressWarnings("unchecked")
+ public static void dumpResponse(List responses) {
+ for (BatchResponse batchResponse : responses) {
+ Object entity = batchResponse.getEntity();
+ if (batchResponse instanceof ChangeSetResponse) {
+ LOGGER.info("Dumping changeset");
+ dumpResponse((List) entity);
+ LOGGER.info("Done with changeset");
+ } else {
+ LOGGER.info("Status =" + batchResponse.getStatus());
+ LOGGER.info("Entity = " + entity);
+ MultivaluedMap headers = batchResponse
+ .getHeaders();
+ if (headers != null) {
+ Set keySet = headers.keySet();
+ LOGGER.info("Headers : ");
+ for (String key : keySet) {
+ List value = headers.get(key);
+ LOGGER.info("Key =" + key + "/t" + "value = " + value);
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/MultipleChangeSetTestCase.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/MultipleChangeSetTestCase.java
new file mode 100644
index 0000000000..761927ae55
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/MultipleChangeSetTestCase.java
@@ -0,0 +1,190 @@
+package org.restlet.test.batch.crud;
+
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.ChangeSetRequestImpl;
+import org.restlet.ext.odata.batch.request.impl.CreateEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.DeleteEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.UpdateEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * The Class MultipleChangeSetTestCase.
+ *
+ * Batch
+ * ---changeset1 :Create
+ * ---changeset2 :Update
+ * ---changeset3 :Delete
+ * Batch ends
+ */
+
+public class MultipleChangeSetTestCase extends RestletTestCase {
+
+ /** The Constant cafeName. */
+ private static final String cafeName = "TestName";
+
+ /** The Constant cafeId. */
+ private static final String cafeId = "40";
+
+ /** The Constant cafeZipCode. */
+ private static final int cafeZipCode = 111111;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger
+ .getLogger(MultipleChangeSetTestCase.class.getName());
+
+ /** The Constant cafeCity. */
+ private static final String cafeCity = "TestCity";
+
+ /** The Constant cafeNameUpdated. */
+ private static final String cafeNameUpdated = "TestName-updated";
+
+ /** Inner component. */
+ private Component component = new Component();
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.restlet.test.RestletTestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test multiple change set.
+ */
+ public void testMultipleChangeSet() {
+ CafeService service = new CafeService();
+
+ // create & delete
+ Cafe cafe = new Cafe();
+ cafe.setId(cafeId);
+ cafe.setName(cafeName);
+ cafe.setCity(cafeCity);
+ cafe.setZipCode(cafeZipCode);
+
+ // create & update
+ Cafe cafeU = new Cafe();
+ cafe.setName(cafeNameUpdated);
+
+ try {
+
+ BatchRequest br = service.createBatchRequest();
+ ChangeSetRequestImpl changeSetRequest1 = new ChangeSetRequestImpl();
+ CreateEntityRequest createEntityRequest = new CreateEntityRequest(
+ service, cafe);
+ changeSetRequest1.addRequest(createEntityRequest);
+ ChangeSetRequestImpl changeSetRequest2 = new ChangeSetRequestImpl();
+ UpdateEntityRequest updateEntityRequest = new UpdateEntityRequest(
+ service, cafeU);
+ changeSetRequest2.addRequest(updateEntityRequest);
+ ChangeSetRequestImpl changeSetRequest3 = new ChangeSetRequestImpl();
+ DeleteEntityRequest deleteEntityRequest = new DeleteEntityRequest(
+ service, cafe);
+ changeSetRequest3.addRequest(deleteEntityRequest);
+ List responses = br.addRequest(changeSetRequest1)
+ .addRequest(changeSetRequest2)
+ .addRequest(changeSetRequest3).execute();
+ dumpResponse(responses);
+
+ // Assert for response-create & delete
+ Query createquery = service.createCafeQuery("/Cafes");
+ Cafe cafe1 = createquery.iterator().next();
+ assertEquals(cafeName, cafe1.getName());
+ assertEquals(cafeId, cafe1.getId());
+ assertEquals(cafeZipCode, cafe1.getZipCode());
+ Response latestResponse = createquery.getService()
+ .getLatestResponse();
+ latestResponse = createquery.getService().getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ Query deletequery = service.deleteCafeQuery(("/Cafes('40')"));
+ latestResponse = deletequery.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK, latestResponse.getStatus());
+
+ // Assert for response-create & update
+ Query createquery2 = service.createCafeQuery("/Cafes");
+ Cafe cafe2 = createquery2.iterator().next();
+ assertEquals(cafeName, cafe2.getName());
+ assertEquals(cafeId, cafe2.getId());
+ assertEquals(cafeZipCode, cafe2.getZipCode());
+ latestResponse = createquery.getService().getLatestResponse();
+ latestResponse = createquery.getService().getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ Query updatequery = service.updateCafeQuery("/Cafes('40')");
+ latestResponse = updatequery.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK, latestResponse.getStatus());
+ } catch (Exception ex) {
+ LOGGER.log(Level.SEVERE, ex.getMessage());
+ Assert.fail();
+ }
+ }
+
+ /**
+ * Dump response.
+ *
+ * @param responses
+ * the responses
+ */
+ @SuppressWarnings("unchecked")
+ public static void dumpResponse(List responses) {
+ for (BatchResponse batchResponse : responses) {
+ Object entity = batchResponse.getEntity();
+ if (batchResponse instanceof ChangeSetResponse) {
+ LOGGER.info("Dumping changeset");
+ dumpResponse((List) entity);
+ LOGGER.info("Done with changeset");
+ } else {
+ LOGGER.info("Status =" + batchResponse.getStatus());
+ LOGGER.info("Entity = " + entity);
+ MultivaluedMap headers = batchResponse
+ .getHeaders();
+ if (headers != null) {
+ Set keySet = headers.keySet();
+ LOGGER.info("Headers : ");
+ for (String key : keySet) {
+ List value = headers.get(key);
+ LOGGER.info("Key =" + key + "/t" + "value = " + value);
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/MultipleChangeSetWithGetTestCase.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/MultipleChangeSetWithGetTestCase.java
new file mode 100644
index 0000000000..144f0a5c05
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/MultipleChangeSetWithGetTestCase.java
@@ -0,0 +1,186 @@
+package org.restlet.test.batch.crud;
+
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.ChangeSetRequestImpl;
+import org.restlet.ext.odata.batch.request.impl.CreateEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.DeleteEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.GetEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.UpdateEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * The Class MultipleChangeSetWithGetTestCase.
+ * Batch---
+ * ---Get entity
+ * ---changeset1 :Create
+ * ---changeset2 :Update
+ * ---changeset3 :Delete
+ * Batch ends
+ *
+ */
+public class MultipleChangeSetWithGetTestCase extends RestletTestCase {
+
+ /** The Constant cafeName. */
+ private static final String cafeName = "TestName";
+
+ /** The Constant cafeId. */
+ private static final String cafeId = "40";
+
+ /** The Constant cafeZipCode. */
+ private static final int cafeZipCode = 111111;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger.getLogger(MultipleChangeSetTestCase.class.getName());
+
+ /** The Constant cafeCity. */
+ private static final String cafeCity = "TestCity";
+
+ /** The Constant cafeNameUpdated. */
+ private static final String cafeNameUpdated = "TestName-updated";
+
+ /** Inner component. */
+ private Component component = new Component();
+
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ /* (non-Javadoc)
+ * @see org.restlet.test.RestletTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test multiple operations with get.
+ */
+ public void testMultipleOperationsWithGet() {
+ CafeService service = new CafeService();
+
+ // create & delete
+ Cafe cafe = new Cafe();
+ cafe.setId(cafeId);
+ cafe.setName(cafeName);
+ cafe.setCity(cafeCity);
+ cafe.setZipCode(cafeZipCode);
+
+ //create & update
+ Cafe cafeU = new Cafe();
+ cafe.setName(cafeNameUpdated);
+
+ try {
+
+ BatchRequest br = service.createBatchRequest();
+ Query getQuery = service.createQuery("/Cafes('40')",Cafe.class);
+ GetEntityRequest getEntityRequest = new GetEntityRequest(getQuery);
+ ChangeSetRequestImpl changeSetRequest1 = new ChangeSetRequestImpl();
+ CreateEntityRequest createEntityRequest = new CreateEntityRequest(service,cafe);
+ changeSetRequest1.addRequest(createEntityRequest);
+ ChangeSetRequestImpl changeSetRequest2 = new ChangeSetRequestImpl();
+ UpdateEntityRequest updateEntityRequest = new UpdateEntityRequest(service, cafeU);
+ changeSetRequest2.addRequest(updateEntityRequest);
+ ChangeSetRequestImpl changeSetRequest3 = new ChangeSetRequestImpl();
+ DeleteEntityRequest deleteEntityRequest = new DeleteEntityRequest(service, cafe);
+ changeSetRequest3.addRequest(deleteEntityRequest);
+ List responses = br.addRequest(getEntityRequest).addRequest(changeSetRequest1).addRequest(changeSetRequest2).addRequest(changeSetRequest3).execute();
+ dumpResponse(responses);
+
+
+ //Assert for response-create & delete
+ Query createquery = service.createCafeQuery("/Cafes");
+ Cafe cafe1=createquery.iterator().next();
+ assertEquals(cafeName, cafe1.getName());
+ assertEquals(cafeId, cafe1.getId());
+ assertEquals(cafeZipCode, cafe1.getZipCode());
+ Response latestResponse = createquery.getService().getLatestResponse();
+ latestResponse = createquery.getService().getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ Query deletequery = service.deleteCafeQuery(("/Cafes('40')"));
+ latestResponse = deletequery.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK,latestResponse.getStatus());
+
+ //Assert for response-create & update
+ Query createquery2 = service.createCafeQuery("/Cafes");
+ Cafe cafe2=createquery2.iterator().next();
+ assertEquals(cafeName, cafe2.getName());
+ assertEquals(cafeId, cafe2.getId());
+ assertEquals(cafeZipCode, cafe2.getZipCode());
+ latestResponse = createquery.getService().getLatestResponse();
+ latestResponse = createquery.getService().getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ Query updatequery = service.updateCafeQuery("/Cafes('40')");
+ latestResponse = updatequery.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK,latestResponse.getStatus());
+ } catch (Exception ex) {
+ LOGGER.log(Level.SEVERE, ex.getMessage());
+ Assert.fail();
+ }
+ }
+
+ /**
+ * Dump response.
+ *
+ * @param responses the responses
+ */
+ @SuppressWarnings("unchecked")
+ public static void dumpResponse(List responses) {
+ for (BatchResponse batchResponse : responses) {
+ Object entity = batchResponse.getEntity();
+ if(batchResponse instanceof ChangeSetResponse){
+ LOGGER.info("Dumping changeset");
+ dumpResponse((List)entity);
+ LOGGER.info("Done with changeset");
+ }else{
+ LOGGER.info("Status ="+ batchResponse.getStatus());
+ LOGGER.info("Entity = "+ entity);
+ MultivaluedMap headers = batchResponse.getHeaders();
+ if(headers!=null){
+ Set keySet = headers.keySet();
+ LOGGER.info("Headers : ");
+ for (String key : keySet) {
+ List value = headers.get(key);
+ LOGGER.info("Key ="+ key + "/t"+"value = "+ value);
+ }
+ }
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/UpdateCafeTestCase.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/UpdateCafeTestCase.java
new file mode 100644
index 0000000000..9be293814e
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/UpdateCafeTestCase.java
@@ -0,0 +1,149 @@
+package org.restlet.test.batch.crud;
+
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.ChangeSetRequestImpl;
+import org.restlet.ext.odata.batch.request.impl.UpdateEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * Test case for RestletBatch service for UPDATE operation on entities.
+ *
+ */
+public class UpdateCafeTestCase extends RestletTestCase {
+
+
+ /** The Constant cafeName. */
+ private static final String cafeName = "TestName";
+
+ /** The Constant cafeNameUpdated. */
+ private static final String cafeNameUpdated = "TestName-updated";
+
+ /** The Constant cafeId. */
+ private static final String cafeId = "40";
+
+ /** The Constant cafeZipCode. */
+ private static final int cafeZipCode = 111111;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger.getLogger(UpdateCafeTestCase.class.getName());
+
+ /** The Constant cafeCity. */
+ private static final String cafeCity = "TestCity";
+
+ /** Inner component. */
+ private Component component = new Component();
+
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ /* (non-Javadoc)
+ * @see org.restlet.test.RestletTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ /* (non-Javadoc)
+ * @see org.restlet.test.RestletTestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test method for UPDATE operation on simple entities.
+ */
+ public void testUpdate() {
+ CafeService service = new CafeService();
+ Cafe cafe = new Cafe();
+ cafe.setId(cafeId);
+ cafe.setName(cafeName);
+ cafe.setCity(cafeCity);
+ cafe.setZipCode(cafeZipCode);
+
+
+ //update
+ Cafe cafeU = new Cafe();
+ cafeU.setId(cafeId);
+ cafeU.setName(cafeName);
+ cafeU.setCity(cafeCity);
+ cafeU.setZipCode(cafeZipCode);
+ cafeU.setName(cafeNameUpdated);
+ try {
+ BatchRequest br = service.createBatchRequest();
+ ChangeSetRequestImpl changeSetRequest = new ChangeSetRequestImpl();
+ UpdateEntityRequest updateEntityRequest = new UpdateEntityRequest(service,cafe);
+ changeSetRequest.addRequest(updateEntityRequest);
+ List responses = br.addRequest(changeSetRequest).execute();
+ dumpResponse(responses);
+
+ Query updatequery = service.updateCafeQuery("/Cafes('40')");
+ Response latestResponse = updatequery.getService().getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ } catch (Exception ex) {
+ LOGGER.log(Level.SEVERE, ex.getMessage());
+ Assert.fail();
+ }
+ }
+
+ /**
+ * Dump response.
+ *
+ * @param responses the responses
+ */
+ @SuppressWarnings("unchecked")
+ public static void dumpResponse(List responses) {
+ for (BatchResponse batchResponse : responses) {
+ Object entity = batchResponse.getEntity();
+ if(batchResponse instanceof ChangeSetResponse){
+ LOGGER.info("Dumping changeset");
+ dumpResponse((List)entity);
+ LOGGER.info("Done with changeset");
+ }else{
+ LOGGER.info("Status ="+ batchResponse.getStatus());
+ LOGGER.info("Entity = "+ entity);
+ MultivaluedMap headers = batchResponse.getHeaders();
+ if(headers!=null){
+ Set keySet = headers.keySet();
+ LOGGER.info("Headers : ");
+ for (String key : keySet) {
+ List value = headers.get(key);
+ LOGGER.info("Key ="+ key + "/t"+"value = "+ value);
+ }
+ }
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/crud/UpdateDeleteChangeSetTestCase.java b/modules/org.restlet.test/src/org/restlet/test/batch/crud/UpdateDeleteChangeSetTestCase.java
new file mode 100644
index 0000000000..b8a98e479e
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/crud/UpdateDeleteChangeSetTestCase.java
@@ -0,0 +1,160 @@
+package org.restlet.test.batch.crud;
+
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.batch.request.BatchRequest;
+import org.restlet.ext.odata.batch.request.impl.ChangeSetRequestImpl;
+import org.restlet.ext.odata.batch.request.impl.DeleteEntityRequest;
+import org.restlet.ext.odata.batch.request.impl.UpdateEntityRequest;
+import org.restlet.ext.odata.batch.response.BatchResponse;
+import org.restlet.ext.odata.batch.response.ChangeSetResponse;
+import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.crud.Cafe;
+
+/**
+ * Test case for RestletBatch service for UPDATE & DELETE operation on entities.
+ *
+ */
+public class UpdateDeleteChangeSetTestCase extends RestletTestCase {
+
+
+ /** The Constant cafeName. */
+ private static final String cafeName = "TestName";
+
+ /** The Constant cafeId. */
+ private static final String cafeId = "40";
+
+ /** The Constant cafeZipCode. */
+ private static final int cafeZipCode = 111111;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = Logger.getLogger(UpdateDeleteChangeSetTestCase.class.getName());
+
+ /** The Constant cafeCity. */
+ private static final String cafeCity = "TestCity";
+
+ /** The Constant cafeNameUpdated. */
+ private static final String cafeNameUpdated = "TestName-updated";
+
+ /** Inner component. */
+ private Component component = new Component();
+
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ /* (non-Javadoc)
+ * @see org.restlet.test.RestletTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ /* (non-Javadoc)
+ * @see org.restlet.test.RestletTestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test method for UPDATE & DELETE operation on simple entities.
+ */
+ public void testUpdateDelete() {
+ CafeService service = new CafeService();
+
+ // Update & Delete
+ Cafe cafe = new Cafe();
+ cafe.setId(cafeId);
+ cafe.setName(cafeName);
+ cafe.setCity(cafeCity);
+ cafe.setZipCode(cafeZipCode);
+
+
+ //update
+ Cafe cafeU = new Cafe();
+ cafe.setName(cafeNameUpdated);
+ try {
+
+ BatchRequest br = service.createBatchRequest();
+ ChangeSetRequestImpl changeSetRequest = new ChangeSetRequestImpl();
+ UpdateEntityRequest updateEntityRequest = new UpdateEntityRequest(service, cafeU);
+ DeleteEntityRequest deleteEntityRequest = new DeleteEntityRequest(service, cafe);
+ changeSetRequest.addRequest(updateEntityRequest);
+ changeSetRequest.addRequest(deleteEntityRequest);
+ List responses = br.addRequest(changeSetRequest).execute();
+ for (BatchResponse batchResponse : responses) {
+ batchResponse.getEntity();
+ dumpResponse(responses);
+ }
+
+ //Assert for response.
+ Query createquery = service.createCafeQuery("/Cafes('40')");
+ Response latestResponse = createquery.getService().getLatestResponse();
+ latestResponse = createquery.getService().getLatestResponse();
+ assertTrue(latestResponse.getStatus().isSuccess());
+ Query updatequery = service.updateCafeQuery("/Cafes('40')");
+ latestResponse = updatequery.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK,latestResponse.getStatus());
+ } catch (Exception ex) {
+ LOGGER.log(Level.SEVERE, ex.getMessage());
+ Assert.fail();
+ }
+ }
+
+ /**
+ * Dump response.
+ *
+ * @param responses the responses
+ */
+ @SuppressWarnings("unchecked")
+ public static void dumpResponse(List responses) {
+ for (BatchResponse batchResponse : responses) {
+ Object entity = batchResponse.getEntity();
+ if(batchResponse instanceof ChangeSetResponse){
+ LOGGER.info("Dumping changeset");
+ dumpResponse((List)entity);
+ LOGGER.info("Done with changeset");
+ }else{
+ LOGGER.info("Status ="+ batchResponse.getStatus());
+ LOGGER.info("Entity = "+ entity);
+ MultivaluedMap headers = batchResponse.getHeaders();
+ if(headers!=null){
+ Set keySet = headers.keySet();
+ LOGGER.info("Headers : ");
+ for (String key : keySet) {
+ List value = headers.get(key);
+ LOGGER.info("Key ="+ key + "/t"+"value = "+ value);
+ }
+ }
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/xml/cafes.xml b/modules/org.restlet.test/src/org/restlet/test/batch/xml/cafes.xml
new file mode 100644
index 0000000000..b7e7f07c33
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/xml/cafes.xml
@@ -0,0 +1,29 @@
+
+
+ Cafes
+ http://localhost:8111/Cafe.svc/Cafes
+ 2010-02-17T11:28:13Z
+
+
+ http://localhost:8111/Cafe.svc/Cafes('40')
+
+ 2010-02-17T11:28:13Z
+
+
+
+
+
+
+
+ 40
+ TestName
+ 111111
+ TestCity
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/xml/cafesUpdatedRequest.xml b/modules/org.restlet.test/src/org/restlet/test/batch/xml/cafesUpdatedRequest.xml
new file mode 100644
index 0000000000..009ccffbbb
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/xml/cafesUpdatedRequest.xml
@@ -0,0 +1,29 @@
+
+
+ Cafes
+ http://localhost:8111/Cafe.svc/Cafes
+ 2010-02-17T11:28:13Z
+
+
+ http://localhost:8111/Cafe.svc/Cafes('40')
+
+ 2010-02-17T11:28:13Z
+
+
+
+
+
+
+
+ 40
+ TestName-updated
+ 111111
+ TestCity
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/xml/createCafeResponse.xml b/modules/org.restlet.test/src/org/restlet/test/batch/xml/createCafeResponse.xml
new file mode 100644
index 0000000000..fb68d6f0ed
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/xml/createCafeResponse.xml
@@ -0,0 +1,24 @@
+
+
+HTTP/1.1 201 Created
+Content-Type: application/atom+xml;charset=utf-8
+Location: http://localhost:8111/Cafe.svc/Cafes('40')
+DataServiceVersion: 3.0
+
+
+http://localhost:8111/Cafe.svc/Cafes('40')
+2014-05-27T09:17:16Z
+
+
+40
+UNKNOWN
+2014-06-23T09:44:08
+
+OWAT
+TestCity
+40
+TestName
+111111
+221
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/xml/deleteCafeResponse.xml b/modules/org.restlet.test/src/org/restlet/test/batch/xml/deleteCafeResponse.xml
new file mode 100644
index 0000000000..507d35844b
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/xml/deleteCafeResponse.xml
@@ -0,0 +1,24 @@
+
+
+HTTP/1.1 200 OK
+Content-Type: application/atom+xml;charset=utf-8
+Location: http://localhost:8111/Cafe.svc/Cafes('40')
+DataServiceVersion: 3.0
+
+
+http://localhost:8111/Cafe.svc/Cafes('40')
+2014-05-27T09:17:16Z
+
+
+40
+UNKNOWN
+2014-06-23T09:44:08
+
+OWAT
+TestCity
+40
+TestName
+111111
+221
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/xml/getCafeResponse.xml b/modules/org.restlet.test/src/org/restlet/test/batch/xml/getCafeResponse.xml
new file mode 100644
index 0000000000..90d32c3d40
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/xml/getCafeResponse.xml
@@ -0,0 +1,24 @@
+
+
+HTTP/1.1 200 OK
+Content-Type: application/xml;charset=utf-8
+Location: http://localhost:8111/Cafe.svc/Cafes('40')
+DataServiceVersion: 3.0
+
+
+http://localhost:8111/Cafe.svc/Cafes('40')
+2014-05-27T09:17:16Z
+
+
+40
+UNKNOWN
+2014-06-23T09:44:08
+
+OWAT
+TestCity
+40
+TestName
+111111
+221
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/xml/metadata.xml b/modules/org.restlet.test/src/org/restlet/test/batch/xml/metadata.xml
new file mode 100644
index 0000000000..4726582e39
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/xml/metadata.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/xml/parentBatchResponse.xml b/modules/org.restlet.test/src/org/restlet/test/batch/xml/parentBatchResponse.xml
new file mode 100644
index 0000000000..a5ab7e7473
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/xml/parentBatchResponse.xml
@@ -0,0 +1,9 @@
+HTTP/1.1 202 Accepted
+Server: Apache-Coyote/1.1
+DataServiceVersion: 3.0
+Content-Type: multipart/mixed;boundary=batchresponse_1f82a90b-43f1-4276-b20a-59da3437dfa8
+Transfer-Encoding: chunked
+Date: Mon, 23 June 2014 09:44:08 GMT
+Proxy-Connection: Keep-Alive
+Connection: Keep-Alive
+
diff --git a/modules/org.restlet.test/src/org/restlet/test/batch/xml/updateCafeResponse.xml b/modules/org.restlet.test/src/org/restlet/test/batch/xml/updateCafeResponse.xml
new file mode 100644
index 0000000000..c6d23e6f34
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/batch/xml/updateCafeResponse.xml
@@ -0,0 +1,27 @@
+
+
+HTTP/1.1 200 OK
+Content-Type: application/atom+xml;charset=utf-8
+Location: http://localhost:8111/Cafe.svc/Cafes('40')
+DataServiceVersion: 3.0
+
+
+http://localhost:8111/Cafe.svc/Cafes('40')
+2014-05-27T09:17:16Z
+
+
+
+40
+UNKNOWN
+2014-06-23T09:44:08
+
+TestName-updated
+OWAT
+TestCity
+40
+TestName
+111111
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataCafeCustoFeedsTestCase.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataCafeCustoFeedsTestCase.java
index 4c40a9a6dd..861aece9a2 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataCafeCustoFeedsTestCase.java
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataCafeCustoFeedsTestCase.java
@@ -34,11 +34,14 @@
package org.restlet.test.ext.odata;
import java.util.Iterator;
+import java.util.List;
import org.restlet.Component;
import org.restlet.data.Protocol;
import org.restlet.ext.odata.Query;
import org.restlet.test.RestletTestCase;
+import org.restlet.test.ext.odata.cafe.Point;
+import org.restlet.test.ext.odata.cafe.StructAny;
import org.restlet.test.ext.odata.cafecustofeeds.Cafe;
import org.restlet.test.ext.odata.cafecustofeeds.CafeCustoFeedsService;
import org.restlet.test.ext.odata.cafecustofeeds.Contact;
@@ -96,6 +99,9 @@ public void testQueryCafes() {
assertEquals("Levallois-Perret", cafe.getCity());
assertEquals(92300, cafe.getZipCode());
+ assertNotNull(cafe.getSpatial());
+ assertComplextTypeParsing(cafe.getSpatial());
+
assertTrue(iterator.hasNext());
cafe = iterator.next();
assertEquals("2", cafe.getId());
@@ -104,6 +110,55 @@ public void testQueryCafes() {
assertEquals("Marly Le Roi", cafe.getCity());
assertEquals(78310, cafe.getZipCode());
}
+
+ /**
+ * This checks that if an entity has a property of complex type.
+ * Also it checks for the collection properties of primitives as well as complex type.
+ *
+ * @param point
+ * complex entity to test.
+ */
+ private void assertComplextTypeParsing(Point point) {
+
+ assertEquals("LINESTRING", point.getGeo_type());
+ assertEquals("GEONAME", point.getGeo_name());
+
+ assertNotNull(point.getX());
+ assertTrue(point.getX().size()>0);
+
+ List listX = point.getX();
+
+ for (Iterator iterator = listX.iterator(); iterator.hasNext();) {
+ Double element = (Double) iterator.next();
+ assertTrue(element instanceof Double);
+ assertNotNull(element);
+ }
+
+ assertNotNull(point.getY());
+ assertTrue(point.getY().size()>0);
+
+ List listY = point.getY();
+
+ for (Iterator iterator = listY.iterator(); iterator.hasNext();) {
+ Double element = (Double) iterator.next();
+ assertTrue(element instanceof Double);
+ assertNotNull(element);
+ }
+
+ assertNotNull(point.getProperties());
+ assertTrue(point.getProperties().size()>0);
+
+ List listComplexObject = point.getProperties();
+
+ for (Iterator iterator = listComplexObject.iterator(); iterator.hasNext();) {
+ StructAny structAny = (StructAny) iterator.next();
+ assertEquals("md", structAny.getName());
+ assertEquals("FLOAT", structAny.getType());
+ assertEquals("meters", structAny.getUnit());
+ assertEquals("depth measure", structAny.getUnitType());
+ assertEquals("[0.0,2670.9678]", structAny.getValues());
+ }
+ }
/**
* Tests the parsing of Feed element with expansion of the one to one
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataCafeTestCase.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataCafeTestCase.java
index 43af095205..535fc5eeb0 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataCafeTestCase.java
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataCafeTestCase.java
@@ -34,7 +34,9 @@
package org.restlet.test.ext.odata;
import java.util.Iterator;
+import java.util.List;
+import org.hamcrest.core.IsInstanceOf;
import org.restlet.Component;
import org.restlet.data.Protocol;
import org.restlet.ext.odata.Query;
@@ -43,6 +45,10 @@
import org.restlet.test.ext.odata.cafe.CafeService;
import org.restlet.test.ext.odata.cafe.Contact;
import org.restlet.test.ext.odata.cafe.Item;
+import org.restlet.test.ext.odata.cafe.Point;
+import org.restlet.test.ext.odata.cafe.StructAny;
+
+import sun.security.jca.GetInstance.Instance;
/**
* Test case for OData service.
@@ -92,6 +98,10 @@ public void testQueryCafes() {
assertEquals("Cafe corp.", cafe.getCompanyName());
assertEquals("Levallois-Perret", cafe.getCity());
assertEquals(92300, cafe.getZipCode());
+
+ //test complex type and collection type (Including collection of simple type as well as complex type).
+ assertNotNull(cafe.getSpatial());
+ assertComplextTypeParsing(cafe.getSpatial());
assertTrue(iterator.hasNext());
cafe = iterator.next();
@@ -103,6 +113,55 @@ public void testQueryCafes() {
}
/**
+ * This checks that if an entity has a property of complex type.
+ * Also it checks for the collection properties of primitives as well as complex type.
+ *
+ * @param point
+ * complex entity to test.
+ */
+ private void assertComplextTypeParsing(Point point) {
+
+ assertEquals("LINESTRING", point.getGeo_type());
+ assertEquals("GEONAME", point.getGeo_name());
+
+ assertNotNull(point.getX());
+ assertTrue(point.getX().size()>0);
+
+ List listX = point.getX();
+
+ for (Iterator iterator = listX.iterator(); iterator.hasNext();) {
+ Double element = (Double) iterator.next();
+ assertTrue(element instanceof Double);
+ assertNotNull(element);
+ }
+
+ assertNotNull(point.getY());
+ assertTrue(point.getY().size()>0);
+
+ List listY = point.getY();
+
+ for (Iterator iterator = listY.iterator(); iterator.hasNext();) {
+ Double element = (Double) iterator.next();
+ assertTrue(element instanceof Double);
+ assertNotNull(element);
+ }
+
+ assertNotNull(point.getProperties());
+ assertTrue(point.getProperties().size()>0);
+
+ List listComplexObject = point.getProperties();
+
+ for (Iterator iterator = listComplexObject.iterator(); iterator.hasNext();) {
+ StructAny structAny = (StructAny) iterator.next();
+ assertEquals("md", structAny.getName());
+ assertEquals("FLOAT", structAny.getType());
+ assertEquals("meters", structAny.getUnit());
+ assertEquals("depth measure", structAny.getUnitType());
+ assertEquals("[0.0,2670.9678]", structAny.getValues());
+ }
+ }
+
+ /**
* Tests the parsing of Feed element with expansion of the one to one
* association "Contact".
*/
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataTestSuite.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataTestSuite.java
index 6238f86d51..31523ca268 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataTestSuite.java
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/ODataTestSuite.java
@@ -33,7 +33,11 @@
package org.restlet.test.ext.odata;
+import org.restlet.test.ext.odata.complexcrud.ODataCafeCrudTestCase;
import org.restlet.test.ext.odata.deepexpand.ODataDeepExpandTestCase;
+import org.restlet.test.ext.odata.function.ActionTestCase;
+import org.restlet.test.ext.odata.function.FunctionTestCase;
+import org.restlet.test.ext.odata.streamcrud.ODataCafeCrudStreamTestCase;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -56,6 +60,11 @@ public static Test suite() {
result.addTestSuite(ODataCafeTestCase.class);
result.addTestSuite(ODataCafeCustoFeedsTestCase.class);
result.addTestSuite(ODataDeepExpandTestCase.class);
+ result.addTestSuite(ODataCafeCrudTestCase.class);
+ result.addTestSuite(org.restlet.test.ext.odata.crud.ODataCafeCrudTestCase.class);
+ result.addTestSuite(ODataCafeCrudStreamTestCase.class);
+ result.addTestSuite(ActionTestCase.class);
+ result.addTestSuite(FunctionTestCase.class);
return result;
}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/Cafe.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/Cafe.java
index 0d349080d5..45a50dd33a 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/Cafe.java
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/Cafe.java
@@ -33,35 +33,28 @@
package org.restlet.test.ext.odata.cafe;
+
+import java.util.ArrayList;
import java.util.List;
import org.restlet.test.ext.odata.cafe.Contact;
import org.restlet.test.ext.odata.cafe.Item;
/**
- * Generated by the generator tool for the WCF Data Services extension for the
- * Restlet framework.
- *
- * @see Metadata of the
- * target WCF Data Services
- *
- */
+* Generated by the generator tool for the WCF Data Services extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
public class Cafe {
- private String city;
-
- private String companyName;
-
- private String id;
-
- private String name;
-
- private int zipCode;
-
- private Contact contact;
-
- private List- items;
-
- /**
+private Point spatial;
+private String city;
+private String companyName;
+private String id;
+private String name;
+private int zipCode;
+private Contact contact;
+private List
- items = new ArrayList
- (); /**
* Constructor without parameter.
*
*/
@@ -79,138 +72,154 @@ public Cafe(String id) {
this();
this.id = id;
}
+
+ /**
+ * Returns the value of the city attribute.
+ *
+ * @return The value of the city attribute.
+ */
+ public String getCity() {
+ return city;
+ }
+
+ /**
+ * Returns the value of the companyName attribute.
+ *
+ * @return The value of the companyName attribute.
+ */
+ public String getCompanyName() {
+ return companyName;
+ }
+
+ /**
+ * Returns the value of the id attribute.
+ *
+ * @return The value of the id attribute.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Returns the value of the name attribute.
+ *
+ * @return The value of the name attribute.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of the zipCode attribute.
+ *
+ * @return The value of the zipCode attribute.
+ */
+ public int getZipCode() {
+ return zipCode;
+ }
+
+ /**
+ * Returns the value of the contact attribute.
+ *
+ * @return The value of the contact attribute.
+ */
+ public Contact getContact() {
+ return contact;
+ }
+
+ /**
+ * Returns the value of the items attribute.
+ *
+ * @return The value of the items attribute.
+ */
+ public List
- getItems() {
+ return items;
+ }
+
+
+ /**
+ * Sets the value of the city attribute.
+ *
+ * @param City
+ * The value of the city attribute.
+ */
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ /**
+ * Sets the value of the companyName attribute.
+ *
+ * @param CompanyName
+ * The value of the companyName attribute.
+ */
+ public void setCompanyName(String companyName) {
+ this.companyName = companyName;
+ }
+
+ /**
+ * Sets the value of the id attribute.
+ *
+ * @param ID
+ * The value of the id attribute.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Sets the value of the name attribute.
+ *
+ * @param Name
+ * The value of the name attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the value of the zipCode attribute.
+ *
+ * @param ZipCode
+ * The value of the zipCode attribute.
+ */
+ public void setZipCode(int zipCode) {
+ this.zipCode = zipCode;
+ }
+
+ /**
+ * Sets the value of the contact attribute.
+ *
+ * @param contact
+ * The value of the contact attribute.
+ */
+ public void setContact(Contact contact) {
+ this.contact = contact;
+ }
+
+ /**
+ * Sets the value of the items attribute.
+ *
+ * @param items
+ * The value of the items attribute.
+ */
+ public void setItems(List
- items) {
+ this.items = items;
+ }
- /**
- * Returns the value of the city attribute.
- *
- * @return The value of the city attribute.
- */
- public String getCity() {
- return city;
- }
-
- /**
- * Returns the value of the companyName attribute.
- *
- * @return The value of the companyName attribute.
- */
- public String getCompanyName() {
- return companyName;
- }
-
- /**
- * Returns the value of the id attribute.
- *
- * @return The value of the id attribute.
- */
- public String getId() {
- return id;
- }
-
- /**
- * Returns the value of the name attribute.
- *
- * @return The value of the name attribute.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the value of the zipCode attribute.
- *
- * @return The value of the zipCode attribute.
- */
- public int getZipCode() {
- return zipCode;
- }
-
- /**
- * Returns the value of the contact attribute.
- *
- * @return The value of the contact attribute.
- */
- public Contact getContact() {
- return contact;
- }
-
- /**
- * Returns the value of the items attribute.
- *
- * @return The value of the items attribute.
- */
- public List
- getItems() {
- return items;
- }
-
- /**
- * Sets the value of the city attribute.
- *
- * @param City
- * The value of the city attribute.
- */
- public void setCity(String city) {
- this.city = city;
- }
-
- /**
- * Sets the value of the companyName attribute.
- *
- * @param CompanyName
- * The value of the companyName attribute.
- */
- public void setCompanyName(String companyName) {
- this.companyName = companyName;
- }
-
- /**
- * Sets the value of the id attribute.
- *
- * @param ID
- * The value of the id attribute.
- */
- public void setId(String id) {
- this.id = id;
- }
-
- /**
- * Sets the value of the name attribute.
- *
- * @param Name
- * The value of the name attribute.
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * Sets the value of the zipCode attribute.
- *
- * @param ZipCode
- * The value of the zipCode attribute.
- */
- public void setZipCode(int zipCode) {
- this.zipCode = zipCode;
- }
+/**
+ * @return the spatial
+ */
+public Point getSpatial() {
+ return spatial;
+}
- /**
- * Sets the value of the contact attribute.
- *
- * @param contact
- * The value of the contact attribute.
- */
- public void setContact(Contact contact) {
- this.contact = contact;
- }
+/**
+ * @param spatial the spatial to set
+ */
+public void setSpatial(Point spatial) {
+ this.spatial = spatial;
+}
- /**
- * Sets the value of the items attribute.
- *
- * @param items
- * The value of the items attribute.
- */
- public void setItems(List
- items) {
- this.items = items;
- }
}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/Point.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/Point.java
new file mode 100644
index 0000000000..c29c4682dd
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/Point.java
@@ -0,0 +1,153 @@
+/**
+ * Copyright 2005-2013 Restlet S.A.S.
+ *
+ * The contents of this file are subject to the terms of one of the following
+ * open source licenses: Apache 2.0 or LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL
+ * 1.0 (the "Licenses"). You can select the license that you prefer but you may
+ * not use this file except in compliance with one of these Licenses.
+ *
+ * You can obtain a copy of the Apache 2.0 license at
+ * http://www.opensource.org/licenses/apache-2.0
+ *
+ * You can obtain a copy of the LGPL 3.0 license at
+ * http://www.opensource.org/licenses/lgpl-3.0
+ *
+ * You can obtain a copy of the LGPL 2.1 license at
+ * http://www.opensource.org/licenses/lgpl-2.1
+ *
+ * You can obtain a copy of the CDDL 1.0 license at
+ * http://www.opensource.org/licenses/cddl1
+ *
+ * You can obtain a copy of the EPL 1.0 license at
+ * http://www.opensource.org/licenses/eclipse-1.0
+ *
+ * See the Licenses for the specific language governing permissions and
+ * limitations under the Licenses.
+ *
+ * Alternatively, you can obtain a royalty free commercial license with less
+ * limitations, transferable or non-transferable, directly at
+ * http://www.restlet.com/products/restlet-framework
+ *
+ * Restlet is a registered trademark of Restlet S.A.S.
+ */
+
+package org.restlet.test.ext.odata.cafe;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* Generated for the OData extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class Point {
+
+ private String geo_type;
+ private String geo_name;
+ private List properties = new ArrayList();
+ private List x = new ArrayList();
+ private List y = new ArrayList();
+
+ /**
+ * Constructor without parameter.
+ *
+ */
+ public Point() {
+ super();
+ }
+
+ /**
+ * Returns the value of the "geo_type" attribute.
+ *
+ * @return The value of the "geo_type" attribute.
+ */
+ public String getGeo_type() {
+ return geo_type;
+ }
+
+
+
+ /**
+ * Returns the value of the "x" attribute.
+ *
+ * @return The value of the "x" attribute.
+ */
+ public List getX() {
+ return x;
+ }
+
+ /**
+ * Returns the value of the "y" attribute.
+ *
+ * @return The value of the "y" attribute.
+ */
+ public List getY() {
+ return y;
+ }
+
+
+
+ /**
+ * Sets the value of the "geo_type" attribute.
+ *
+ * @param geo_type
+ * The value of the "geo_type" attribute.
+ */
+ public void setGeo_type(String geo_type) {
+ this.geo_type = geo_type;
+ }
+
+
+
+ /**
+ * Sets the value of the "x" attribute.
+ *
+ * @param x
+ * The value of the "x" attribute.
+ */
+ public void setX(List x) {
+ this.x = x;
+ }
+
+ /**
+ * Sets the value of the "y" attribute.
+ *
+ * @param y
+ * The value of the "y" attribute.
+ */
+ public void setY(List y) {
+ this.y = y;
+ }
+
+
+/**
+ * @return the geo_name
+ */
+public String getGeo_name() {
+ return geo_name;
+}
+
+/**
+ * @param geo_name the geo_name to set
+ */
+public void setGeo_name(String geo_name) {
+ this.geo_name = geo_name;
+}
+
+/**
+ * @return the properties
+ */
+public List getProperties() {
+ return properties;
+}
+
+/**
+ * @param properties the properties to set
+ */
+public void setProperties(List properties) {
+ this.properties = properties;
+}
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/StructAny.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/StructAny.java
new file mode 100644
index 0000000000..894b4f1f38
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/StructAny.java
@@ -0,0 +1,156 @@
+/**
+ * Copyright 2005-2013 Restlet S.A.S.
+ *
+ * The contents of this file are subject to the terms of one of the following
+ * open source licenses: Apache 2.0 or LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL
+ * 1.0 (the "Licenses"). You can select the license that you prefer but you may
+ * not use this file except in compliance with one of these Licenses.
+ *
+ * You can obtain a copy of the Apache 2.0 license at
+ * http://www.opensource.org/licenses/apache-2.0
+ *
+ * You can obtain a copy of the LGPL 3.0 license at
+ * http://www.opensource.org/licenses/lgpl-3.0
+ *
+ * You can obtain a copy of the LGPL 2.1 license at
+ * http://www.opensource.org/licenses/lgpl-2.1
+ *
+ * You can obtain a copy of the CDDL 1.0 license at
+ * http://www.opensource.org/licenses/cddl1
+ *
+ * You can obtain a copy of the EPL 1.0 license at
+ * http://www.opensource.org/licenses/eclipse-1.0
+ *
+ * See the Licenses for the specific language governing permissions and
+ * limitations under the Licenses.
+ *
+ * Alternatively, you can obtain a royalty free commercial license with less
+ * limitations, transferable or non-transferable, directly at
+ * http://www.restlet.com/products/restlet-framework
+ *
+ * Restlet is a registered trademark of Restlet S.A.S.
+ */
+
+package org.restlet.test.ext.odata.cafe;
+
+
+
+/**
+* Generated for the OData extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class StructAny {
+
+ private String name;
+ private String type;
+ private String unit;
+ private String unitType;
+ private String values;
+
+ /**
+ * Constructor without parameter.
+ *
+ */
+ public StructAny() {
+ super();
+ }
+
+ /**
+ * Returns the value of the "name" attribute.
+ *
+ * @return The value of the "name" attribute.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of the "type" attribute.
+ *
+ * @return The value of the "type" attribute.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the value of the "unit" attribute.
+ *
+ * @return The value of the "unit" attribute.
+ */
+ public String getUnit() {
+ return unit;
+ }
+
+ /**
+ * Returns the value of the "unitType" attribute.
+ *
+ * @return The value of the "unitType" attribute.
+ */
+ public String getUnitType() {
+ return unitType;
+ }
+
+ /**
+ * Returns the value of the "values" attribute.
+ *
+ * @return The value of the "values" attribute.
+ */
+ public String getValues() {
+ return values;
+ }
+
+
+ /**
+ * Sets the value of the "name" attribute.
+ *
+ * @param name
+ * The value of the "name" attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the value of the "type" attribute.
+ *
+ * @param type
+ * The value of the "type" attribute.
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Sets the value of the "unit" attribute.
+ *
+ * @param unit
+ * The value of the "unit" attribute.
+ */
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+ /**
+ * Sets the value of the "unitType" attribute.
+ *
+ * @param unitType
+ * The value of the "unitType" attribute.
+ */
+ public void setUnitType(String unitType) {
+ this.unitType = unitType;
+ }
+
+ /**
+ * Sets the value of the "values" attribute.
+ *
+ * @param values
+ * The value of the "values" attribute.
+ */
+ public void setValues(String values) {
+ this.values = values;
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/cafes.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/cafes.xml
index d9b633cd59..8760e32983 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/cafes.xml
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/cafes.xml
@@ -27,6 +27,27 @@
92300
Levallois-Perret
Cafe corp.
+
+ LINESTRING
+ GEONAME
+
+ 7.29
+ 7.29
+
+
+ 65.32000000000001
+ 65.32000000000001
+
+
+
+ md
+ FLOAT
+ meters
+ depth measure
+ [0.0,2670.9678]
+
+
+
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/metadata.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/metadata.xml
index fd3ddcb1d4..102f4e8e88 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/metadata.xml
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafe/metadata.xml
@@ -60,6 +60,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/Cafe.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/Cafe.java
index 765bc876be..5c774b5121 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/Cafe.java
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/Cafe.java
@@ -33,35 +33,30 @@
package org.restlet.test.ext.odata.cafecustofeeds;
+
+import java.util.ArrayList;
import java.util.List;
+
+import org.restlet.test.ext.odata.cafe.Point;
import org.restlet.test.ext.odata.cafecustofeeds.Contact;
import org.restlet.test.ext.odata.cafecustofeeds.Item;
/**
- * Generated by the generator tool for the WCF Data Services extension for the
- * Restlet framework.
- *
- * @see Metadata of
- * the target WCF Data Services
- *
- */
+* Generated by the generator tool for the WCF Data Services extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
public class Cafe {
- private String city;
-
- private String companyName;
-
- private String id;
-
- private String name;
-
- private int zipCode;
-
- private Contact contact;
-
- private List- items;
-
- /**
+private Point spatial;
+private String city;
+private String companyName;
+private String id;
+private String name;
+private int zipCode;
+private Contact contact;
+private List
- items = new ArrayList
- (); /**
* Constructor without parameter.
*
*/
@@ -79,138 +74,154 @@ public Cafe(String id) {
this();
this.id = id;
}
+
+ /**
+ * Returns the value of the city attribute.
+ *
+ * @return The value of the city attribute.
+ */
+ public String getCity() {
+ return city;
+ }
+
+ /**
+ * Returns the value of the companyName attribute.
+ *
+ * @return The value of the companyName attribute.
+ */
+ public String getCompanyName() {
+ return companyName;
+ }
+
+ /**
+ * Returns the value of the id attribute.
+ *
+ * @return The value of the id attribute.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Returns the value of the name attribute.
+ *
+ * @return The value of the name attribute.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of the zipCode attribute.
+ *
+ * @return The value of the zipCode attribute.
+ */
+ public int getZipCode() {
+ return zipCode;
+ }
+
+ /**
+ * Returns the value of the contact attribute.
+ *
+ * @return The value of the contact attribute.
+ */
+ public Contact getContact() {
+ return contact;
+ }
+
+ /**
+ * Returns the value of the items attribute.
+ *
+ * @return The value of the items attribute.
+ */
+ public List
- getItems() {
+ return items;
+ }
+
+
+ /**
+ * Sets the value of the city attribute.
+ *
+ * @param City
+ * The value of the city attribute.
+ */
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ /**
+ * Sets the value of the companyName attribute.
+ *
+ * @param CompanyName
+ * The value of the companyName attribute.
+ */
+ public void setCompanyName(String companyName) {
+ this.companyName = companyName;
+ }
+
+ /**
+ * Sets the value of the id attribute.
+ *
+ * @param ID
+ * The value of the id attribute.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Sets the value of the name attribute.
+ *
+ * @param Name
+ * The value of the name attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the value of the zipCode attribute.
+ *
+ * @param ZipCode
+ * The value of the zipCode attribute.
+ */
+ public void setZipCode(int zipCode) {
+ this.zipCode = zipCode;
+ }
+
+ /**
+ * Sets the value of the contact attribute.
+ *
+ * @param contact
+ * The value of the contact attribute.
+ */
+ public void setContact(Contact contact) {
+ this.contact = contact;
+ }
+
+ /**
+ * Sets the value of the items attribute.
+ *
+ * @param items
+ * The value of the items attribute.
+ */
+ public void setItems(List
- items) {
+ this.items = items;
+ }
- /**
- * Returns the value of the city attribute.
- *
- * @return The value of the city attribute.
- */
- public String getCity() {
- return city;
- }
-
- /**
- * Returns the value of the companyName attribute.
- *
- * @return The value of the companyName attribute.
- */
- public String getCompanyName() {
- return companyName;
- }
-
- /**
- * Returns the value of the id attribute.
- *
- * @return The value of the id attribute.
- */
- public String getId() {
- return id;
- }
-
- /**
- * Returns the value of the name attribute.
- *
- * @return The value of the name attribute.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the value of the zipCode attribute.
- *
- * @return The value of the zipCode attribute.
- */
- public int getZipCode() {
- return zipCode;
- }
-
- /**
- * Returns the value of the contact attribute.
- *
- * @return The value of the contact attribute.
- */
- public Contact getContact() {
- return contact;
- }
-
- /**
- * Returns the value of the items attribute.
- *
- * @return The value of the items attribute.
- */
- public List
- getItems() {
- return items;
- }
-
- /**
- * Sets the value of the city attribute.
- *
- * @param City
- * The value of the city attribute.
- */
- public void setCity(String city) {
- this.city = city;
- }
-
- /**
- * Sets the value of the companyName attribute.
- *
- * @param CompanyName
- * The value of the companyName attribute.
- */
- public void setCompanyName(String companyName) {
- this.companyName = companyName;
- }
-
- /**
- * Sets the value of the id attribute.
- *
- * @param ID
- * The value of the id attribute.
- */
- public void setId(String id) {
- this.id = id;
- }
-
- /**
- * Sets the value of the name attribute.
- *
- * @param Name
- * The value of the name attribute.
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * Sets the value of the zipCode attribute.
- *
- * @param ZipCode
- * The value of the zipCode attribute.
- */
- public void setZipCode(int zipCode) {
- this.zipCode = zipCode;
- }
+/**
+ * @return the spatial
+ */
+public Point getSpatial() {
+ return spatial;
+}
- /**
- * Sets the value of the contact attribute.
- *
- * @param contact
- * The value of the contact attribute.
- */
- public void setContact(Contact contact) {
- this.contact = contact;
- }
+/**
+ * @param spatial the spatial to set
+ */
+public void setSpatial(Point spatial) {
+ this.spatial = spatial;
+}
- /**
- * Sets the value of the items attribute.
- *
- * @param items
- * The value of the items attribute.
- */
- public void setItems(List
- items) {
- this.items = items;
- }
}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/Point.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/Point.java
new file mode 100644
index 0000000000..7d5c316c1e
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/Point.java
@@ -0,0 +1,153 @@
+/**
+ * Copyright 2005-2013 Restlet S.A.S.
+ *
+ * The contents of this file are subject to the terms of one of the following
+ * open source licenses: Apache 2.0 or LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL
+ * 1.0 (the "Licenses"). You can select the license that you prefer but you may
+ * not use this file except in compliance with one of these Licenses.
+ *
+ * You can obtain a copy of the Apache 2.0 license at
+ * http://www.opensource.org/licenses/apache-2.0
+ *
+ * You can obtain a copy of the LGPL 3.0 license at
+ * http://www.opensource.org/licenses/lgpl-3.0
+ *
+ * You can obtain a copy of the LGPL 2.1 license at
+ * http://www.opensource.org/licenses/lgpl-2.1
+ *
+ * You can obtain a copy of the CDDL 1.0 license at
+ * http://www.opensource.org/licenses/cddl1
+ *
+ * You can obtain a copy of the EPL 1.0 license at
+ * http://www.opensource.org/licenses/eclipse-1.0
+ *
+ * See the Licenses for the specific language governing permissions and
+ * limitations under the Licenses.
+ *
+ * Alternatively, you can obtain a royalty free commercial license with less
+ * limitations, transferable or non-transferable, directly at
+ * http://www.restlet.com/products/restlet-framework
+ *
+ * Restlet is a registered trademark of Restlet S.A.S.
+ */
+
+package org.restlet.test.ext.odata.cafecustofeeds;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* Generated for the OData extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class Point {
+
+ private String geo_type;
+ private String geo_name;
+ private List properties = new ArrayList();
+ private List x = new ArrayList();
+ private List y = new ArrayList();
+
+ /**
+ * Constructor without parameter.
+ *
+ */
+ public Point() {
+ super();
+ }
+
+ /**
+ * Returns the value of the "geo_type" attribute.
+ *
+ * @return The value of the "geo_type" attribute.
+ */
+ public String getGeo_type() {
+ return geo_type;
+ }
+
+
+
+ /**
+ * Returns the value of the "x" attribute.
+ *
+ * @return The value of the "x" attribute.
+ */
+ public List getX() {
+ return x;
+ }
+
+ /**
+ * Returns the value of the "y" attribute.
+ *
+ * @return The value of the "y" attribute.
+ */
+ public List getY() {
+ return y;
+ }
+
+
+
+ /**
+ * Sets the value of the "geo_type" attribute.
+ *
+ * @param geo_type
+ * The value of the "geo_type" attribute.
+ */
+ public void setGeo_type(String geo_type) {
+ this.geo_type = geo_type;
+ }
+
+
+
+ /**
+ * Sets the value of the "x" attribute.
+ *
+ * @param x
+ * The value of the "x" attribute.
+ */
+ public void setX(List x) {
+ this.x = x;
+ }
+
+ /**
+ * Sets the value of the "y" attribute.
+ *
+ * @param y
+ * The value of the "y" attribute.
+ */
+ public void setY(List y) {
+ this.y = y;
+ }
+
+
+/**
+ * @return the geo_name
+ */
+public String getGeo_name() {
+ return geo_name;
+}
+
+/**
+ * @param geo_name the geo_name to set
+ */
+public void setGeo_name(String geo_name) {
+ this.geo_name = geo_name;
+}
+
+/**
+ * @return the properties
+ */
+public List getProperties() {
+ return properties;
+}
+
+/**
+ * @param properties the properties to set
+ */
+public void setProperties(List properties) {
+ this.properties = properties;
+}
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/StructAny.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/StructAny.java
new file mode 100644
index 0000000000..9923968026
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/StructAny.java
@@ -0,0 +1,156 @@
+/**
+ * Copyright 2005-2013 Restlet S.A.S.
+ *
+ * The contents of this file are subject to the terms of one of the following
+ * open source licenses: Apache 2.0 or LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL
+ * 1.0 (the "Licenses"). You can select the license that you prefer but you may
+ * not use this file except in compliance with one of these Licenses.
+ *
+ * You can obtain a copy of the Apache 2.0 license at
+ * http://www.opensource.org/licenses/apache-2.0
+ *
+ * You can obtain a copy of the LGPL 3.0 license at
+ * http://www.opensource.org/licenses/lgpl-3.0
+ *
+ * You can obtain a copy of the LGPL 2.1 license at
+ * http://www.opensource.org/licenses/lgpl-2.1
+ *
+ * You can obtain a copy of the CDDL 1.0 license at
+ * http://www.opensource.org/licenses/cddl1
+ *
+ * You can obtain a copy of the EPL 1.0 license at
+ * http://www.opensource.org/licenses/eclipse-1.0
+ *
+ * See the Licenses for the specific language governing permissions and
+ * limitations under the Licenses.
+ *
+ * Alternatively, you can obtain a royalty free commercial license with less
+ * limitations, transferable or non-transferable, directly at
+ * http://www.restlet.com/products/restlet-framework
+ *
+ * Restlet is a registered trademark of Restlet S.A.S.
+ */
+
+package org.restlet.test.ext.odata.cafecustofeeds;
+
+
+
+/**
+* Generated for the OData extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class StructAny {
+
+ private String name;
+ private String type;
+ private String unit;
+ private String unitType;
+ private String values;
+
+ /**
+ * Constructor without parameter.
+ *
+ */
+ public StructAny() {
+ super();
+ }
+
+ /**
+ * Returns the value of the "name" attribute.
+ *
+ * @return The value of the "name" attribute.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of the "type" attribute.
+ *
+ * @return The value of the "type" attribute.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the value of the "unit" attribute.
+ *
+ * @return The value of the "unit" attribute.
+ */
+ public String getUnit() {
+ return unit;
+ }
+
+ /**
+ * Returns the value of the "unitType" attribute.
+ *
+ * @return The value of the "unitType" attribute.
+ */
+ public String getUnitType() {
+ return unitType;
+ }
+
+ /**
+ * Returns the value of the "values" attribute.
+ *
+ * @return The value of the "values" attribute.
+ */
+ public String getValues() {
+ return values;
+ }
+
+
+ /**
+ * Sets the value of the "name" attribute.
+ *
+ * @param name
+ * The value of the "name" attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the value of the "type" attribute.
+ *
+ * @param type
+ * The value of the "type" attribute.
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Sets the value of the "unit" attribute.
+ *
+ * @param unit
+ * The value of the "unit" attribute.
+ */
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+ /**
+ * Sets the value of the "unitType" attribute.
+ *
+ * @param unitType
+ * The value of the "unitType" attribute.
+ */
+ public void setUnitType(String unitType) {
+ this.unitType = unitType;
+ }
+
+ /**
+ * Sets the value of the "values" attribute.
+ *
+ * @param values
+ * The value of the "values" attribute.
+ */
+ public void setValues(String values) {
+ this.values = values;
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/cafes.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/cafes.xml
index 147cb3d95d..b5b9b91ffa 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/cafes.xml
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/cafes.xml
@@ -26,6 +26,27 @@
Le Cafe Louis
92300
Levallois-Perret
+
+ LINESTRING
+ GEONAME
+
+ 7.29
+ 7.29
+
+
+ 65.32000000000001
+ 65.32000000000001
+
+
+
+ md
+ FLOAT
+ meters
+ depth measure
+ [0.0,2670.9678]
+
+
+
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/metadata.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/metadata.xml
index a2415d1278..f9fb5ca635 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/metadata.xml
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/cafecustofeeds/metadata.xml
@@ -70,6 +70,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/Cafe.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/Cafe.java
new file mode 100644
index 0000000000..f49496db75
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/Cafe.java
@@ -0,0 +1,158 @@
+package org.restlet.test.ext.odata.complexcrud;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.restlet.test.ext.odata.cafe.Item;
+
+/**
+* Generated by the generator tool for the WCF Data Services extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class Cafe {
+
+private Point spatial;
+private String city;
+
+private String id;
+private String name;
+private int zipCode;
+
+private List- items = new ArrayList
- (); /**
+ * Constructor without parameter.
+ *
+ */
+ public Cafe() {
+ super();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id
+ * The identifiant value of the entity.
+ */
+ public Cafe(String id) {
+ this();
+ this.id = id;
+ }
+
+ /**
+ * Returns the value of the city attribute.
+ *
+ * @return The value of the city attribute.
+ */
+ public String getCity() {
+ return city;
+ }
+
+
+ /**
+ * Returns the value of the id attribute.
+ *
+ * @return The value of the id attribute.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Returns the value of the name attribute.
+ *
+ * @return The value of the name attribute.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of the zipCode attribute.
+ *
+ * @return The value of the zipCode attribute.
+ */
+ public int getZipCode() {
+ return zipCode;
+ }
+
+
+ /**
+ * Returns the value of the items attribute.
+ *
+ * @return The value of the items attribute.
+ */
+ public List
- getItems() {
+ return items;
+ }
+
+
+ /**
+ * Sets the value of the city attribute.
+ *
+ * @param City
+ * The value of the city attribute.
+ */
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+
+ /**
+ * Sets the value of the id attribute.
+ *
+ * @param ID
+ * The value of the id attribute.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Sets the value of the name attribute.
+ *
+ * @param Name
+ * The value of the name attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the value of the zipCode attribute.
+ *
+ * @param ZipCode
+ * The value of the zipCode attribute.
+ */
+ public void setZipCode(int zipCode) {
+ this.zipCode = zipCode;
+ }
+
+
+ /**
+ * Sets the value of the items attribute.
+ *
+ * @param items
+ * The value of the items attribute.
+ */
+ public void setItems(List
- items) {
+ this.items = items;
+ }
+
+/**
+ * @return the spatial
+ */
+public Point getSpatial() {
+ return spatial;
+}
+
+/**
+ * @param spatial the spatial to set
+ */
+public void setSpatial(Point spatial) {
+ this.spatial = spatial;
+}
+
+
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/CafeCrudApplication.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/CafeCrudApplication.java
new file mode 100644
index 0000000000..af7c45bc0f
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/CafeCrudApplication.java
@@ -0,0 +1,87 @@
+package org.restlet.test.ext.odata.complexcrud;
+
+import java.io.IOException;
+
+import org.restlet.Application;
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.Restlet;
+import org.restlet.data.CharacterSet;
+import org.restlet.data.Form;
+import org.restlet.data.LocalReference;
+import org.restlet.data.Method;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.routing.Router;
+
+/**
+ * Sample application that simulates cud operation for complex entities and
+ * collection.
+ */
+public class CafeCrudApplication extends Application {
+ private static class MyClapRestlet extends Restlet {
+ String file;
+
+ @SuppressWarnings("unused")
+ boolean updatable;
+
+ public MyClapRestlet(Context context, String file, boolean updatable) {
+ super(context);
+ this.file = file;
+ this.updatable = updatable;
+ }
+
+ @SuppressWarnings("unused")
+ @Override
+ public void handle(Request request, Response response) {
+
+ if (Method.GET.equals(request.getMethod())) {
+ Form form = request.getResourceRef().getQueryAsForm();
+ String uri = "/"
+ + this.getClass().getPackage().getName()
+ .replace(".", "/") + "/" + file;
+
+ Response r = getContext().getClientDispatcher().handle(
+ new Request(Method.GET, LocalReference
+ .createClapReference(LocalReference.CLAP_CLASS,
+ uri + ".xml")));
+ response.setEntity(r.getEntity());
+ response.setStatus(r.getStatus());
+
+ } else if (Method.POST.equals(request.getMethod()) || Method.PUT.equals(request.getMethod())) {
+ String rep=null;
+ try {
+ rep = request.getEntity().getText();
+ } catch (IOException e) {
+ response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+ }
+ if(null != rep && !rep.isEmpty()){
+ response.setStatus(Status.SUCCESS_OK);
+ }
+
+ } else if (Method.DELETE.equals(request.getMethod())) {
+ response.setStatus(Status.SUCCESS_NO_CONTENT);
+
+ }
+
+ }
+ }
+
+
+ @Override
+ public Restlet createInboundRoot() {
+ getMetadataService().setDefaultCharacterSet(CharacterSet.ISO_8859_1);
+ getConnectorService().getClientProtocols().add(Protocol.CLAP);
+ Router router = new Router(getContext());
+
+ router.attach("/$metadata", new MyClapRestlet(getContext(), "metadata",
+ true));
+ router.attach("/Cafes", new MyClapRestlet(getContext(), "cafes", true));
+ router.attach("/Cafes('30')", new MyClapRestlet(getContext(),
+ "cafesUpdated", true));
+
+ return router;
+ }
+
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/CafeService.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/CafeService.java
new file mode 100644
index 0000000000..705b72739b
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/CafeService.java
@@ -0,0 +1,44 @@
+package org.restlet.test.ext.odata.complexcrud;
+
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.Service;
+
+/**
+* Generated by the generator tool for the WCF Data Services extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class CafeService extends Service {
+
+ /**
+ * Constructor.
+ *
+ */
+ public CafeService() {
+ super("http://localhost:8111/Cafe.svc");
+ }
+
+ /**
+ * Adds a new entity to the service.
+ *
+ * @param entity
+ * The entity to add to the service.
+ * @throws Exception
+ */
+ public void addEntity(Cafe entity) throws Exception {
+ addEntity("/Cafes", entity);
+ }
+
+ /**
+ * Creates a query for cafe entities hosted by this service.
+ *
+ * @param subpath
+ * The path to this entity relatively to the service URI.
+ * @return A query object.
+ */
+ public Query createCafeQuery(String subpath) {
+ return createQuery(subpath, Cafe.class);
+ }
+
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/ODataCafeCrudTestCase.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/ODataCafeCrudTestCase.java
new file mode 100644
index 0000000000..e13c133ea0
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/ODataCafeCrudTestCase.java
@@ -0,0 +1,142 @@
+package org.restlet.test.ext.odata.complexcrud;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Context;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.ext.odata.Query;
+import org.restlet.test.RestletTestCase;
+
+/**
+ * Test case for OData service for CUD operation on complex entities and
+ * collection.
+ *
+ */
+public class ODataCafeCrudTestCase extends RestletTestCase {
+
+ /** Inner component. */
+ private Component component = new Component();
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test method for crud operation on complex entities and collection.
+ */
+ public void testCrudComplexEntity() {
+ CafeService service = new CafeService();
+
+ // create.
+ Cafe cafe = buildCafeEntity();
+
+ try {
+ service.addEntity(cafe);
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot add entity due to: " + e.getMessage());
+ Assert.fail();
+ }
+
+ Query query = service.createCafeQuery("/Cafes");
+ Cafe cafe1 = query.iterator().next();
+ assertEquals("TestName", cafe1.getName());
+ assertEquals("30", cafe1.getId());
+ assertEquals(111111, cafe1.getZipCode());
+ assertNotNull(cafe1.getSpatial());
+ Response latestResponse = query.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK, latestResponse.getStatus());
+
+ // // Update.
+ cafe1.setName("TestName-update");
+
+ try {
+ service.updateEntity(cafe1);
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot update entity due to: " + e.getMessage());
+ Assert.fail();
+ }
+
+ Query query3 = service.createCafeQuery("/Cafes('30')");
+
+ Cafe cafe2 = query3.iterator().next();
+ assertEquals("TestName-updated", cafe2.getName());
+ assertNotNull(cafe1.getSpatial());
+ latestResponse = query3.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK, latestResponse.getStatus());
+
+ // Delete
+ try {
+ service.deleteEntity(cafe2);
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot delete entity due to: " + e.getMessage());
+ Assert.fail();
+ }
+ latestResponse = query3.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_NO_CONTENT, latestResponse.getStatus());
+ }
+
+ private Cafe buildCafeEntity() {
+ Cafe cafe = new Cafe();
+ cafe.setId("30");
+ cafe.setName("TestName");
+ cafe.setCity("TestCity");
+ cafe.setZipCode(111111);
+
+ Point point = new Point();
+ point.setGeo_name("GEONAME");
+ point.setGeo_type("LINESTRING");
+
+ StructAny structAny = new StructAny();
+ structAny.setName("md");
+ structAny.setType("FLOAT");
+ structAny.setUnit("meters");
+ structAny.setUnitType("depth measure");
+ structAny.setValues("[0.0,2670.9678]");
+
+ List properties = new ArrayList();
+ properties.add(structAny);
+
+ List x = new ArrayList();
+ x.add(7.29d);
+ x.add(7.29d);
+ List y = new ArrayList();
+ y.add(65.32000000000001d);
+ y.add(65.32000000000001d);
+
+ point.setProperties(properties);
+ point.setX(x);
+ point.setY(y);
+ cafe.setSpatial(point);
+ return cafe;
+ }
+
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/Point.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/Point.java
new file mode 100644
index 0000000000..ab85b873b5
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/Point.java
@@ -0,0 +1,120 @@
+package org.restlet.test.ext.odata.complexcrud;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* Generated for the OData extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class Point {
+
+ private String geo_type;
+ private String geo_name;
+ private List properties = new ArrayList();
+ private List x = new ArrayList();
+ private List y = new ArrayList();
+
+ /**
+ * Constructor without parameter.
+ *
+ */
+ public Point() {
+ super();
+ }
+
+ /**
+ * Returns the value of the "geo_type" attribute.
+ *
+ * @return The value of the "geo_type" attribute.
+ */
+ public String getGeo_type() {
+ return geo_type;
+ }
+
+
+
+ /**
+ * Returns the value of the "x" attribute.
+ *
+ * @return The value of the "x" attribute.
+ */
+ public List getX() {
+ return x;
+ }
+
+ /**
+ * Returns the value of the "y" attribute.
+ *
+ * @return The value of the "y" attribute.
+ */
+ public List getY() {
+ return y;
+ }
+
+
+
+ /**
+ * Sets the value of the "geo_type" attribute.
+ *
+ * @param geo_type
+ * The value of the "geo_type" attribute.
+ */
+ public void setGeo_type(String geo_type) {
+ this.geo_type = geo_type;
+ }
+
+
+
+ /**
+ * Sets the value of the "x" attribute.
+ *
+ * @param x
+ * The value of the "x" attribute.
+ */
+ public void setX(List x) {
+ this.x = x;
+ }
+
+ /**
+ * Sets the value of the "y" attribute.
+ *
+ * @param y
+ * The value of the "y" attribute.
+ */
+ public void setY(List y) {
+ this.y = y;
+ }
+
+
+/**
+ * @return the geo_name
+ */
+public String getGeo_name() {
+ return geo_name;
+}
+
+/**
+ * @param geo_name the geo_name to set
+ */
+public void setGeo_name(String geo_name) {
+ this.geo_name = geo_name;
+}
+
+/**
+ * @return the properties
+ */
+public List getProperties() {
+ return properties;
+}
+
+/**
+ * @param properties the properties to set
+ */
+public void setProperties(List properties) {
+ this.properties = properties;
+}
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/StructAny.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/StructAny.java
new file mode 100644
index 0000000000..495e5c22c4
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/StructAny.java
@@ -0,0 +1,124 @@
+
+package org.restlet.test.ext.odata.complexcrud;
+
+
+
+/**
+* Generated for the OData extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class StructAny {
+
+ private String name;
+ private String type;
+ private String unit;
+ private String unitType;
+ private String values;
+
+ /**
+ * Constructor without parameter.
+ *
+ */
+ public StructAny() {
+ super();
+ }
+
+ /**
+ * Returns the value of the "name" attribute.
+ *
+ * @return The value of the "name" attribute.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of the "type" attribute.
+ *
+ * @return The value of the "type" attribute.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the value of the "unit" attribute.
+ *
+ * @return The value of the "unit" attribute.
+ */
+ public String getUnit() {
+ return unit;
+ }
+
+ /**
+ * Returns the value of the "unitType" attribute.
+ *
+ * @return The value of the "unitType" attribute.
+ */
+ public String getUnitType() {
+ return unitType;
+ }
+
+ /**
+ * Returns the value of the "values" attribute.
+ *
+ * @return The value of the "values" attribute.
+ */
+ public String getValues() {
+ return values;
+ }
+
+
+ /**
+ * Sets the value of the "name" attribute.
+ *
+ * @param name
+ * The value of the "name" attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the value of the "type" attribute.
+ *
+ * @param type
+ * The value of the "type" attribute.
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Sets the value of the "unit" attribute.
+ *
+ * @param unit
+ * The value of the "unit" attribute.
+ */
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+ /**
+ * Sets the value of the "unitType" attribute.
+ *
+ * @param unitType
+ * The value of the "unitType" attribute.
+ */
+ public void setUnitType(String unitType) {
+ this.unitType = unitType;
+ }
+
+ /**
+ * Sets the value of the "values" attribute.
+ *
+ * @param values
+ * The value of the "values" attribute.
+ */
+ public void setValues(String values) {
+ this.values = values;
+ }
+
+}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/cafes.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/cafes.xml
new file mode 100644
index 0000000000..4724c0e3d2
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/cafes.xml
@@ -0,0 +1,51 @@
+
+
+ Cafes
+ http://localhost:8111/Cafe.svc/Cafes
+ 2010-02-17T11:28:13Z
+
+
+ http://localhost:8111/Cafe.svc/Cafes('30')
+
+ 2010-02-17T11:28:13Z
+
+
+
+
+
+
+
+ 30
+ TestName
+ 111111
+ TestCity
+
+
+ LINESTRING
+ GEONAME
+
+
+ md
+ FLOAT
+ meters
+ depth measure
+ [0.0,2670.9678]
+
+
+
+ 7.29
+ 7.29
+
+
+ 65.32000000000001
+ 65.32000000000001
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/cafesUpdated.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/cafesUpdated.xml
new file mode 100644
index 0000000000..89aecc6c8d
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/cafesUpdated.xml
@@ -0,0 +1,51 @@
+
+
+ Cafes
+ http://localhost:8111/Cafe.svc/Cafes
+ 2010-02-17T11:28:13Z
+
+
+ http://localhost:8111/Cafe.svc/Cafes('30')
+
+ 2010-02-17T11:28:13Z
+
+
+
+
+
+
+
+ 30
+ TestName-updated
+ 111111
+ TestCity
+
+
+ LINESTRING
+ GEONAME
+
+
+ md
+ FLOAT
+ meters
+ depth measure
+ [0.0,2670.9678]
+
+
+
+ 7.29
+ 7.29
+
+
+ 65.32000000000001
+ 65.32000000000001
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/metadata.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/metadata.xml
new file mode 100644
index 0000000000..b66f86e1f6
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/complexcrud/metadata.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/Cafe.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/Cafe.java
new file mode 100644
index 0000000000..28bb59e32e
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/Cafe.java
@@ -0,0 +1,120 @@
+package org.restlet.test.ext.odata.crud;
+
+
+
+/**
+* Generated by the generator tool for the WCF Data Services extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class Cafe {
+
+
+private String city;
+
+private String id;
+private String name;
+private int zipCode;
+
+/**
+ * Constructor without parameter.
+ *
+ */
+ public Cafe() {
+ super();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id
+ * The identifiant value of the entity.
+ */
+ public Cafe(String id) {
+ this();
+ this.id = id;
+ }
+
+ /**
+ * Returns the value of the city attribute.
+ *
+ * @return The value of the city attribute.
+ */
+ public String getCity() {
+ return city;
+ }
+
+
+ /**
+ * Returns the value of the id attribute.
+ *
+ * @return The value of the id attribute.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Returns the value of the name attribute.
+ *
+ * @return The value of the name attribute.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of the zipCode attribute.
+ *
+ * @return The value of the zipCode attribute.
+ */
+ public int getZipCode() {
+ return zipCode;
+ }
+
+
+
+
+ /**
+ * Sets the value of the city attribute.
+ *
+ * @param City
+ * The value of the city attribute.
+ */
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+
+
+ /**
+ * Sets the value of the id attribute.
+ *
+ * @param ID
+ * The value of the id attribute.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Sets the value of the name attribute.
+ *
+ * @param Name
+ * The value of the name attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the value of the zipCode attribute.
+ *
+ * @param ZipCode
+ * The value of the zipCode attribute.
+ */
+ public void setZipCode(int zipCode) {
+ this.zipCode = zipCode;
+ }
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/CafeCrudApplication.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/CafeCrudApplication.java
new file mode 100644
index 0000000000..2d85bfeedc
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/CafeCrudApplication.java
@@ -0,0 +1,84 @@
+
+package org.restlet.test.ext.odata.crud;
+
+import java.io.IOException;
+
+import org.restlet.Application;
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.Restlet;
+import org.restlet.data.CharacterSet;
+import org.restlet.data.LocalReference;
+import org.restlet.data.Method;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.routing.Router;
+
+/**
+ * Sample application that simulates the CUD operation on entities.
+ *
+ */
+@SuppressWarnings("unused")
+public class CafeCrudApplication extends Application {
+
+ private static class MyClapRestlet extends Restlet {
+ String file;
+
+ boolean updatable;
+
+ public MyClapRestlet(Context context, String file, boolean updatable) {
+ super(context);
+ this.file = file;
+ this.updatable = updatable;
+ }
+
+ @Override
+ public void handle(Request request, Response response) {
+ if (Method.GET.equals(request.getMethod())) {
+ String uri = "/"
+ + this.getClass().getPackage().getName()
+ .replace(".", "/") + "/" + file;
+
+ Response r = getContext().getClientDispatcher().handle(
+ new Request(Method.GET, LocalReference
+ .createClapReference(LocalReference.CLAP_CLASS,
+ uri + ".xml")));
+ response.setEntity(r.getEntity());
+ response.setStatus(r.getStatus());
+
+ } else if (Method.POST.equals(request.getMethod()) || Method.PUT.equals(request.getMethod())) {
+ String rep=null;
+ try {
+ rep = request.getEntity().getText();
+ } catch (IOException e) {
+ response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+ }
+ if(null != rep && !rep.isEmpty()){
+ response.setStatus(Status.SUCCESS_OK);
+ }
+
+ } else if (Method.DELETE.equals(request.getMethod())) {
+ response.setStatus(Status.SUCCESS_NO_CONTENT);
+
+ }
+
+ }
+ }
+
+ @Override
+ public Restlet createInboundRoot() {
+ getMetadataService().setDefaultCharacterSet(CharacterSet.ISO_8859_1);
+ getConnectorService().getClientProtocols().add(Protocol.CLAP);
+ Router router = new Router(getContext());
+
+ router.attach("/$metadata", new MyClapRestlet(getContext(), "metadata",
+ true));
+ router.attach("/Cafes", new MyClapRestlet(getContext(), "cafes", true));
+ router.attach("/Cafes('30')", new MyClapRestlet(getContext(),
+ "cafesUpdated", true));
+
+ return router;
+ }
+
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/CafeService.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/CafeService.java
new file mode 100644
index 0000000000..27228381d0
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/CafeService.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright 2005-2013 Restlet S.A.S.
+ *
+ * The contents of this file are subject to the terms of one of the following
+ * open source licenses: Apache 2.0 or LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL
+ * 1.0 (the "Licenses"). You can select the license that you prefer but you may
+ * not use this file except in compliance with one of these Licenses.
+ *
+ * You can obtain a copy of the Apache 2.0 license at
+ * http://www.opensource.org/licenses/apache-2.0
+ *
+ * You can obtain a copy of the LGPL 3.0 license at
+ * http://www.opensource.org/licenses/lgpl-3.0
+ *
+ * You can obtain a copy of the LGPL 2.1 license at
+ * http://www.opensource.org/licenses/lgpl-2.1
+ *
+ * You can obtain a copy of the CDDL 1.0 license at
+ * http://www.opensource.org/licenses/cddl1
+ *
+ * You can obtain a copy of the EPL 1.0 license at
+ * http://www.opensource.org/licenses/eclipse-1.0
+ *
+ * See the Licenses for the specific language governing permissions and
+ * limitations under the Licenses.
+ *
+ * Alternatively, you can obtain a royalty free commercial license with less
+ * limitations, transferable or non-transferable, directly at
+ * http://www.restlet.com/products/restlet-framework
+ *
+ * Restlet is a registered trademark of Restlet S.A.S.
+ */
+
+package org.restlet.test.ext.odata.crud;
+
+import org.restlet.ext.odata.Query;
+import org.restlet.ext.odata.Service;
+
+/**
+* Generated by the generator tool for the WCF Data Services extension for the Restlet framework.
+*
+* @see Metadata of the target WCF Data Services
+*
+*/
+public class CafeService extends Service {
+
+ /**
+ * Constructor.
+ *
+ */
+ public CafeService() {
+ super("http://localhost:8111/Cafe.svc");
+ }
+
+ /**
+ * Adds a new entity to the service.
+ *
+ * @param entity
+ * The entity to add to the service.
+ * @throws Exception
+ */
+ public void addEntity(Cafe entity) throws Exception {
+ addEntity("/Cafes", entity);
+ }
+
+ /**
+ * Creates a query for cafe entities hosted by this service.
+ *
+ * @param subpath
+ * The path to this entity relatively to the service URI.
+ * @return A query object.
+ */
+ public Query createCafeQuery(String subpath) {
+ return createQuery(subpath, Cafe.class);
+ }
+
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/ODataCafeCrudTestCase.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/ODataCafeCrudTestCase.java
new file mode 100644
index 0000000000..aa4dbd0ddb
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/ODataCafeCrudTestCase.java
@@ -0,0 +1,102 @@
+package org.restlet.test.ext.odata.crud;
+
+import junit.framework.Assert;
+
+import org.restlet.Component;
+import org.restlet.Context;
+import org.restlet.Response;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.ext.odata.Query;
+import org.restlet.test.RestletTestCase;
+
+/**
+ * Test case for OData service for CUD operation on entities.
+ *
+ */
+public class ODataCafeCrudTestCase extends RestletTestCase {
+
+ /** Inner component. */
+ private Component component = new Component();
+
+ /** OData service used for all tests. */
+ @SuppressWarnings("unused")
+ private CafeService service;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ component.getServers().add(Protocol.HTTP, 8111);
+ component.getClients().add(Protocol.CLAP);
+ component.getDefaultHost().attach("/Cafe.svc",
+ new CafeCrudApplication());
+ component.start();
+
+ service = new CafeService();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ component.stop();
+ component = null;
+ super.tearDown();
+ }
+
+ /**
+ * Test method for crud operation on simple entities.
+ */
+ public void testCrudSimpleEntity() {
+ CafeService service = new CafeService();
+
+ // create.
+ Cafe cafe = new Cafe();
+ cafe.setId("30");
+ cafe.setName("TestName");
+ cafe.setCity("TestCity");
+ cafe.setZipCode(111111);
+ try {
+ service.addEntity(cafe);
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot add entity due to: " + e.getMessage());
+ Assert.fail();
+ }
+
+ Query query = service.createCafeQuery("/Cafes");
+ Cafe cafe1 = query.iterator().next();
+ assertEquals("TestName", cafe1.getName());
+ assertEquals("30", cafe1.getId());
+ assertEquals(111111, cafe1.getZipCode());
+ Response latestResponse = query.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK, latestResponse.getStatus());
+ // // Update.
+ cafe1.setName("TestName-update");
+
+ try {
+ service.updateEntity(cafe1);
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot update entity due to: " + e.getMessage());
+ Assert.fail();
+ }
+
+ Query query3 = service.createCafeQuery("/Cafes('30')");
+
+ Cafe cafe2 = query3.iterator().next();
+ assertEquals("TestName-updated", cafe2.getName());
+ latestResponse = query3.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_OK, latestResponse.getStatus());
+ // Delete
+ try {
+ service.deleteEntity(cafe2);
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot delete entity due to: " + e.getMessage());
+ Assert.fail();
+ }
+ latestResponse = query3.getService().getLatestResponse();
+ assertEquals(Status.SUCCESS_NO_CONTENT, latestResponse.getStatus());
+ }
+
+}
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/cafes.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/cafes.xml
new file mode 100644
index 0000000000..1098176fde
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/cafes.xml
@@ -0,0 +1,29 @@
+
+
+ Cafes
+ http://localhost:8111/Cafe.svc/Cafes
+ 2010-02-17T11:28:13Z
+
+
+ http://localhost:8111/Cafe.svc/Cafes('30')
+
+ 2010-02-17T11:28:13Z
+
+
+
+
+
+
+
+ 30
+ TestName
+ 111111
+ TestCity
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/cafesUpdated.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/cafesUpdated.xml
new file mode 100644
index 0000000000..95493e94db
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/cafesUpdated.xml
@@ -0,0 +1,29 @@
+
+
+ Cafes
+ http://localhost:8111/Cafe.svc/Cafes
+ 2010-02-17T11:28:13Z
+
+
+ http://localhost:8111/Cafe.svc/Cafes('30')
+
+ 2010-02-17T11:28:13Z
+
+
+
+
+
+
+
+ 30
+ TestName-updated
+ 111111
+ TestCity
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/metadata.xml b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/metadata.xml
new file mode 100644
index 0000000000..8ec48f6592
--- /dev/null
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/crud/metadata.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/ActivitySector.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/ActivitySector.java
index 8ad98c3082..7900119bae 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/ActivitySector.java
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/ActivitySector.java
@@ -33,6 +33,8 @@
package org.restlet.test.ext.odata.deepexpand.model;
+
+import java.util.ArrayList;
import java.util.List;
import org.restlet.test.ext.odata.deepexpand.model.ActivitySector;
@@ -54,11 +56,8 @@ public class ActivitySector {
private String description;
private int id;
-
- private List childActivitySectors;
-
- private List companies;
-
+ private List childActivitySectors = new ArrayList();
+ private List companies = new ArrayList();
private ActivitySector parentActivitySector;
/**
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/AuthenticatedUser.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/AuthenticatedUser.java
index ecc0eb50c0..70989b52a2 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/AuthenticatedUser.java
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/AuthenticatedUser.java
@@ -33,6 +33,8 @@
package org.restlet.test.ext.odata.deepexpand.model;
+
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -45,51 +47,31 @@
import org.restlet.test.ext.odata.deepexpand.model.Telephone;
/**
- * Generated by the generator tool for the OData extension for the Restlet
- * framework.
- *
- * @see Metadata
- * of the target OData service
- *
- */
+* Generated by the generator tool for the OData extension for the Restlet framework.
+*
+* @see Metadata of the target OData service
+*
+*/
public class AuthenticatedUser {
private Date dateOfBirth;
-
private String email;
-
private String fatherName;
-
private String gender;
-
private int id;
-
private String motherName;
-
private String name;
-
private String notes;
-
private String surname;
-
private String userName;
-
private Tracking tracking;
-
- private List addresses;
-
+ private List addresses = new ArrayList();
private CoOp defaultCoOp;
-
private Department department;
-
private Language preferredLanguage;
-
- private List reports;
-
- private List roles;
-
- private List telephones;
+ private List reports = new ArrayList();
+ private List roles = new ArrayList();
+ private List telephones = new ArrayList();
/**
* Constructor without parameter.
@@ -110,346 +92,325 @@ public AuthenticatedUser(int id) {
this.id = id;
}
- /**
- * Returns the value of the "dateOfBirth" attribute.
- *
- * @return The value of the "dateOfBirth" attribute.
- */
- public Date getDateOfBirth() {
- return dateOfBirth;
- }
-
- /**
- * Returns the value of the "email" attribute.
- *
- * @return The value of the "email" attribute.
- */
- public String getEmail() {
- return email;
- }
-
- /**
- * Returns the value of the "fatherName" attribute.
- *
- * @return The value of the "fatherName" attribute.
- */
- public String getFatherName() {
- return fatherName;
- }
-
- /**
- * Returns the value of the "gender" attribute.
- *
- * @return The value of the "gender" attribute.
- */
- public String getGender() {
- return gender;
- }
-
- /**
- * Returns the value of the "id" attribute.
- *
- * @return The value of the "id" attribute.
- */
- public int getId() {
- return id;
- }
-
- /**
- * Returns the value of the "motherName" attribute.
- *
- * @return The value of the "motherName" attribute.
- */
- public String getMotherName() {
- return motherName;
- }
-
- /**
- * Returns the value of the "name" attribute.
- *
- * @return The value of the "name" attribute.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the value of the "notes" attribute.
- *
- * @return The value of the "notes" attribute.
- */
- public String getNotes() {
- return notes;
- }
-
- /**
- * Returns the value of the "surname" attribute.
- *
- * @return The value of the "surname" attribute.
- */
- public String getSurname() {
- return surname;
- }
-
- /**
- * Returns the value of the "userName" attribute.
- *
- * @return The value of the "userName" attribute.
- */
- public String getUserName() {
- return userName;
- }
-
- /**
- * Returns the value of the "tracking" attribute.
- *
- * @return The value of the "tracking" attribute.
- */
- public Tracking getTracking() {
- return tracking;
- }
-
- /**
- * Returns the value of the "addresses" attribute.
- *
- * @return The value of the "addresses" attribute.
- */
- public List getAddresses() {
- return addresses;
- }
-
- /**
- * Returns the value of the "defaultCoOp" attribute.
- *
- * @return The value of the "defaultCoOp" attribute.
- */
- public CoOp getDefaultCoOp() {
- return defaultCoOp;
- }
-
- /**
- * Returns the value of the "department" attribute.
- *
- * @return The value of the "department" attribute.
- */
- public Department getDepartment() {
- return department;
- }
-
- /**
- * Returns the value of the "preferredLanguage" attribute.
- *
- * @return The value of the "preferredLanguage" attribute.
- */
- public Language getPreferredLanguage() {
- return preferredLanguage;
- }
-
- /**
- * Returns the value of the "reports" attribute.
- *
- * @return The value of the "reports" attribute.
- */
- public List getReports() {
- return reports;
- }
-
- /**
- * Returns the value of the "roles" attribute.
- *
- * @return The value of the "roles" attribute.
- */
- public List getRoles() {
- return roles;
- }
-
- /**
- * Returns the value of the "telephones" attribute.
- *
- * @return The value of the "telephones" attribute.
- */
- public List getTelephones() {
- return telephones;
- }
-
- /**
- * Sets the value of the "dateOfBirth" attribute.
- *
- * @param dateOfBirth
- * The value of the "dateOfBirth" attribute.
- */
- public void setDateOfBirth(Date dateOfBirth) {
- this.dateOfBirth = dateOfBirth;
- }
-
- /**
- * Sets the value of the "email" attribute.
- *
- * @param email
- * The value of the "email" attribute.
- */
- public void setEmail(String email) {
- this.email = email;
- }
-
- /**
- * Sets the value of the "fatherName" attribute.
- *
- * @param fatherName
- * The value of the "fatherName" attribute.
- */
- public void setFatherName(String fatherName) {
- this.fatherName = fatherName;
- }
-
- /**
- * Sets the value of the "gender" attribute.
- *
- * @param gender
- * The value of the "gender" attribute.
- */
- public void setGender(String gender) {
- this.gender = gender;
- }
-
- /**
- * Sets the value of the "id" attribute.
- *
- * @param id
- * The value of the "id" attribute.
- */
- public void setId(int id) {
- this.id = id;
- }
-
- /**
- * Sets the value of the "motherName" attribute.
- *
- * @param motherName
- * The value of the "motherName" attribute.
- */
- public void setMotherName(String motherName) {
- this.motherName = motherName;
- }
-
- /**
- * Sets the value of the "name" attribute.
- *
- * @param name
- * The value of the "name" attribute.
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * Sets the value of the "notes" attribute.
- *
- * @param notes
- * The value of the "notes" attribute.
- */
- public void setNotes(String notes) {
- this.notes = notes;
- }
-
- /**
- * Sets the value of the "surname" attribute.
- *
- * @param surname
- * The value of the "surname" attribute.
- */
- public void setSurname(String surname) {
- this.surname = surname;
- }
-
- /**
- * Sets the value of the "userName" attribute.
- *
- * @param userName
- * The value of the "userName" attribute.
- */
- public void setUserName(String userName) {
- this.userName = userName;
- }
-
- /**
- * Sets the value of the "tracking" attribute.
- *
- * @param tracking
- * The value of the "tracking" attribute.
- */
- public void setTracking(Tracking tracking) {
- this.tracking = tracking;
- }
-
- /**
- * Sets the value of the "addresses" attribute.
- *
- * @param addresses
- * " The value of the "addresses" attribute.
- */
- public void setAddresses(List addresses) {
- this.addresses = addresses;
- }
-
- /**
- * Sets the value of the "defaultCoOp" attribute.
- *
- * @param defaultCoOp
- * " The value of the "defaultCoOp" attribute.
- */
- public void setDefaultCoOp(CoOp defaultCoOp) {
- this.defaultCoOp = defaultCoOp;
- }
-
- /**
- * Sets the value of the "department" attribute.
- *
- * @param department
- * " The value of the "department" attribute.
- */
- public void setDepartment(Department department) {
- this.department = department;
- }
-
- /**
- * Sets the value of the "preferredLanguage" attribute.
- *
- * @param preferredLanguage
- * " The value of the "preferredLanguage" attribute.
- */
- public void setPreferredLanguage(Language preferredLanguage) {
- this.preferredLanguage = preferredLanguage;
- }
-
- /**
- * Sets the value of the "reports" attribute.
- *
- * @param reports
- * " The value of the "reports" attribute.
- */
- public void setReports(List reports) {
- this.reports = reports;
- }
-
- /**
- * Sets the value of the "roles" attribute.
- *
- * @param roles
- * " The value of the "roles" attribute.
- */
- public void setRoles(List roles) {
- this.roles = roles;
- }
-
- /**
- * Sets the value of the "telephones" attribute.
- *
- * @param telephones
- * " The value of the "telephones" attribute.
- */
- public void setTelephones(List telephones) {
- this.telephones = telephones;
- }
+ /**
+ * Returns the value of the "dateOfBirth" attribute.
+ *
+ * @return The value of the "dateOfBirth" attribute.
+ */
+ public Date getDateOfBirth() {
+ return dateOfBirth;
+ }
+ /**
+ * Returns the value of the "email" attribute.
+ *
+ * @return The value of the "email" attribute.
+ */
+ public String getEmail() {
+ return email;
+ }
+ /**
+ * Returns the value of the "fatherName" attribute.
+ *
+ * @return The value of the "fatherName" attribute.
+ */
+ public String getFatherName() {
+ return fatherName;
+ }
+ /**
+ * Returns the value of the "gender" attribute.
+ *
+ * @return The value of the "gender" attribute.
+ */
+ public String getGender() {
+ return gender;
+ }
+ /**
+ * Returns the value of the "id" attribute.
+ *
+ * @return The value of the "id" attribute.
+ */
+ public int getId() {
+ return id;
+ }
+ /**
+ * Returns the value of the "motherName" attribute.
+ *
+ * @return The value of the "motherName" attribute.
+ */
+ public String getMotherName() {
+ return motherName;
+ }
+ /**
+ * Returns the value of the "name" attribute.
+ *
+ * @return The value of the "name" attribute.
+ */
+ public String getName() {
+ return name;
+ }
+ /**
+ * Returns the value of the "notes" attribute.
+ *
+ * @return The value of the "notes" attribute.
+ */
+ public String getNotes() {
+ return notes;
+ }
+ /**
+ * Returns the value of the "surname" attribute.
+ *
+ * @return The value of the "surname" attribute.
+ */
+ public String getSurname() {
+ return surname;
+ }
+ /**
+ * Returns the value of the "userName" attribute.
+ *
+ * @return The value of the "userName" attribute.
+ */
+ public String getUserName() {
+ return userName;
+ }
+ /**
+ * Returns the value of the "tracking" attribute.
+ *
+ * @return The value of the "tracking" attribute.
+ */
+ public Tracking getTracking() {
+ return tracking;
+ }
+ /**
+ * Returns the value of the "addresses" attribute.
+ *
+ * @return The value of the "addresses" attribute.
+ */
+ public List getAddresses() {
+ return addresses;
+ }
+
+ /**
+ * Returns the value of the "defaultCoOp" attribute.
+ *
+ * @return The value of the "defaultCoOp" attribute.
+ */
+ public CoOp getDefaultCoOp() {
+ return defaultCoOp;
+ }
+
+ /**
+ * Returns the value of the "department" attribute.
+ *
+ * @return The value of the "department" attribute.
+ */
+ public Department getDepartment() {
+ return department;
+ }
+
+ /**
+ * Returns the value of the "preferredLanguage" attribute.
+ *
+ * @return The value of the "preferredLanguage" attribute.
+ */
+ public Language getPreferredLanguage() {
+ return preferredLanguage;
+ }
+
+ /**
+ * Returns the value of the "reports" attribute.
+ *
+ * @return The value of the "reports" attribute.
+ */
+ public List getReports() {
+ return reports;
+ }
+
+ /**
+ * Returns the value of the "roles" attribute.
+ *
+ * @return The value of the "roles" attribute.
+ */
+ public List getRoles() {
+ return roles;
+ }
+
+ /**
+ * Returns the value of the "telephones" attribute.
+ *
+ * @return The value of the "telephones" attribute.
+ */
+ public List getTelephones() {
+ return telephones;
+ }
+
+ /**
+ * Sets the value of the "dateOfBirth" attribute.
+ *
+ * @param dateOfBirth
+ * The value of the "dateOfBirth" attribute.
+ */
+ public void setDateOfBirth(Date dateOfBirth) {
+ this.dateOfBirth = dateOfBirth;
+ }
+ /**
+ * Sets the value of the "email" attribute.
+ *
+ * @param email
+ * The value of the "email" attribute.
+ */
+ public void setEmail(String email) {
+ this.email = email;
+ }
+ /**
+ * Sets the value of the "fatherName" attribute.
+ *
+ * @param fatherName
+ * The value of the "fatherName" attribute.
+ */
+ public void setFatherName(String fatherName) {
+ this.fatherName = fatherName;
+ }
+ /**
+ * Sets the value of the "gender" attribute.
+ *
+ * @param gender
+ * The value of the "gender" attribute.
+ */
+ public void setGender(String gender) {
+ this.gender = gender;
+ }
+ /**
+ * Sets the value of the "id" attribute.
+ *
+ * @param id
+ * The value of the "id" attribute.
+ */
+ public void setId(int id) {
+ this.id = id;
+ }
+ /**
+ * Sets the value of the "motherName" attribute.
+ *
+ * @param motherName
+ * The value of the "motherName" attribute.
+ */
+ public void setMotherName(String motherName) {
+ this.motherName = motherName;
+ }
+ /**
+ * Sets the value of the "name" attribute.
+ *
+ * @param name
+ * The value of the "name" attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+ /**
+ * Sets the value of the "notes" attribute.
+ *
+ * @param notes
+ * The value of the "notes" attribute.
+ */
+ public void setNotes(String notes) {
+ this.notes = notes;
+ }
+ /**
+ * Sets the value of the "surname" attribute.
+ *
+ * @param surname
+ * The value of the "surname" attribute.
+ */
+ public void setSurname(String surname) {
+ this.surname = surname;
+ }
+ /**
+ * Sets the value of the "userName" attribute.
+ *
+ * @param userName
+ * The value of the "userName" attribute.
+ */
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+ /**
+ * Sets the value of the "tracking" attribute.
+ *
+ * @param tracking
+ * The value of the "tracking" attribute.
+ */
+ public void setTracking(Tracking tracking) {
+ this.tracking = tracking;
+ }
+
+ /**
+ * Sets the value of the "addresses" attribute.
+ *
+ * @param addresses"
+ * The value of the "addresses" attribute.
+ */
+ public void setAddresses(List addresses) {
+ this.addresses = addresses;
+ }
+
+ /**
+ * Sets the value of the "defaultCoOp" attribute.
+ *
+ * @param defaultCoOp"
+ * The value of the "defaultCoOp" attribute.
+ */
+ public void setDefaultCoOp(CoOp defaultCoOp) {
+ this.defaultCoOp = defaultCoOp;
+ }
+
+ /**
+ * Sets the value of the "department" attribute.
+ *
+ * @param department"
+ * The value of the "department" attribute.
+ */
+ public void setDepartment(Department department) {
+ this.department = department;
+ }
+
+ /**
+ * Sets the value of the "preferredLanguage" attribute.
+ *
+ * @param preferredLanguage"
+ * The value of the "preferredLanguage" attribute.
+ */
+ public void setPreferredLanguage(Language preferredLanguage) {
+ this.preferredLanguage = preferredLanguage;
+ }
+
+ /**
+ * Sets the value of the "reports" attribute.
+ *
+ * @param reports"
+ * The value of the "reports" attribute.
+ */
+ public void setReports(List reports) {
+ this.reports = reports;
+ }
+
+ /**
+ * Sets the value of the "roles" attribute.
+ *
+ * @param roles"
+ * The value of the "roles" attribute.
+ */
+ public void setRoles(List roles) {
+ this.roles = roles;
+ }
+
+ /**
+ * Sets the value of the "telephones" attribute.
+ *
+ * @param telephones"
+ * The value of the "telephones" attribute.
+ */
+ public void setTelephones(List telephones) {
+ this.telephones = telephones;
+ }
}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/Branch.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/Branch.java
index fc18b61cf0..931c13ffb6 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/Branch.java
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/Branch.java
@@ -33,6 +33,8 @@
package org.restlet.test.ext.odata.deepexpand.model;
+
+import java.util.ArrayList;
import java.util.List;
import org.restlet.test.ext.odata.deepexpand.model.Company;
@@ -42,35 +44,23 @@
import org.restlet.test.ext.odata.deepexpand.model.Multilingual;
/**
- * Generated by the generator tool for the OData extension for the Restlet
- * framework.
- *
- * @see Metadata
- * of the target OData service
- *
- */
+* Generated by the generator tool for the OData extension for the Restlet framework.
+*
+* @see Metadata of the target OData service
+*
+*/
public class Branch {
private String fax;
-
private int id;
-
private String telephone;
-
private EmbeddableAddress address;
-
private Tracking tracking;
-
private Company company;
-
- private List jobParts;
-
- private List jobPostingParts;
-
+ private List jobParts = new ArrayList();
+ private List jobPostingParts = new ArrayList();
private Multilingual name;
-
- private List persons;
+ private List persons = new ArrayList();
/**
* Constructor without parameter.
@@ -91,194 +81,186 @@ public Branch(int id) {
this.id = id;
}
- /**
- * Returns the value of the "fax" attribute.
- *
- * @return The value of the "fax" attribute.
- */
- public String getFax() {
- return fax;
- }
-
- /**
- * Returns the value of the "id" attribute.
- *
- * @return The value of the "id" attribute.
- */
- public int getId() {
- return id;
- }
-
- /**
- * Returns the value of the "telephone" attribute.
- *
- * @return The value of the "telephone" attribute.
- */
- public String getTelephone() {
- return telephone;
- }
-
- /**
- * Returns the value of the "address" attribute.
- *
- * @return The value of the "address" attribute.
- */
- public EmbeddableAddress getAddress() {
- return address;
- }
-
- /**
- * Returns the value of the "tracking" attribute.
- *
- * @return The value of the "tracking" attribute.
- */
- public Tracking getTracking() {
- return tracking;
- }
-
- /**
- * Returns the value of the "company" attribute.
- *
- * @return The value of the "company" attribute.
- */
- public Company getCompany() {
- return company;
- }
-
- /**
- * Returns the value of the "jobParts" attribute.
- *
- * @return The value of the "jobParts" attribute.
- */
- public List getJobParts() {
- return jobParts;
- }
-
- /**
- * Returns the value of the "jobPostingParts" attribute.
- *
- * @return The value of the "jobPostingParts" attribute.
- */
- public List getJobPostingParts() {
- return jobPostingParts;
- }
-
- /**
- * Returns the value of the "name" attribute.
- *
- * @return The value of the "name" attribute.
- */
- public Multilingual getName() {
- return name;
- }
-
- /**
- * Returns the value of the "persons" attribute.
- *
- * @return The value of the "persons" attribute.
- */
- public List getPersons() {
- return persons;
- }
-
- /**
- * Sets the value of the "fax" attribute.
- *
- * @param fax
- * The value of the "fax" attribute.
- */
- public void setFax(String fax) {
- this.fax = fax;
- }
-
- /**
- * Sets the value of the "id" attribute.
- *
- * @param id
- * The value of the "id" attribute.
- */
- public void setId(int id) {
- this.id = id;
- }
-
- /**
- * Sets the value of the "telephone" attribute.
- *
- * @param telephone
- * The value of the "telephone" attribute.
- */
- public void setTelephone(String telephone) {
- this.telephone = telephone;
- }
-
- /**
- * Sets the value of the "address" attribute.
- *
- * @param address
- * The value of the "address" attribute.
- */
- public void setAddress(EmbeddableAddress address) {
- this.address = address;
- }
-
- /**
- * Sets the value of the "tracking" attribute.
- *
- * @param tracking
- * The value of the "tracking" attribute.
- */
- public void setTracking(Tracking tracking) {
- this.tracking = tracking;
- }
-
- /**
- * Sets the value of the "company" attribute.
- *
- * @param company
- * " The value of the "company" attribute.
- */
- public void setCompany(Company company) {
- this.company = company;
- }
-
- /**
- * Sets the value of the "jobParts" attribute.
- *
- * @param jobParts
- * " The value of the "jobParts" attribute.
- */
- public void setJobParts(List jobParts) {
- this.jobParts = jobParts;
- }
-
- /**
- * Sets the value of the "jobPostingParts" attribute.
- *
- * @param jobPostingParts
- * " The value of the "jobPostingParts" attribute.
- */
- public void setJobPostingParts(List jobPostingParts) {
- this.jobPostingParts = jobPostingParts;
- }
-
- /**
- * Sets the value of the "name" attribute.
- *
- * @param name
- * " The value of the "name" attribute.
- */
- public void setName(Multilingual name) {
- this.name = name;
- }
-
- /**
- * Sets the value of the "persons" attribute.
- *
- * @param persons
- * " The value of the "persons" attribute.
- */
- public void setPersons(List persons) {
- this.persons = persons;
- }
+ /**
+ * Returns the value of the "fax" attribute.
+ *
+ * @return The value of the "fax" attribute.
+ */
+ public String getFax() {
+ return fax;
+ }
+ /**
+ * Returns the value of the "id" attribute.
+ *
+ * @return The value of the "id" attribute.
+ */
+ public int getId() {
+ return id;
+ }
+ /**
+ * Returns the value of the "telephone" attribute.
+ *
+ * @return The value of the "telephone" attribute.
+ */
+ public String getTelephone() {
+ return telephone;
+ }
+ /**
+ * Returns the value of the "address" attribute.
+ *
+ * @return The value of the "address" attribute.
+ */
+ public EmbeddableAddress getAddress() {
+ return address;
+ }
+ /**
+ * Returns the value of the "tracking" attribute.
+ *
+ * @return The value of the "tracking" attribute.
+ */
+ public Tracking getTracking() {
+ return tracking;
+ }
+ /**
+ * Returns the value of the "company" attribute.
+ *
+ * @return The value of the "company" attribute.
+ */
+ public Company getCompany() {
+ return company;
+ }
+
+ /**
+ * Returns the value of the "jobParts" attribute.
+ *
+ * @return The value of the "jobParts" attribute.
+ */
+ public List getJobParts() {
+ return jobParts;
+ }
+
+ /**
+ * Returns the value of the "jobPostingParts" attribute.
+ *
+ * @return The value of the "jobPostingParts" attribute.
+ */
+ public List getJobPostingParts() {
+ return jobPostingParts;
+ }
+
+ /**
+ * Returns the value of the "name" attribute.
+ *
+ * @return The value of the "name" attribute.
+ */
+ public Multilingual getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of the "persons" attribute.
+ *
+ * @return The value of the "persons" attribute.
+ */
+ public List getPersons() {
+ return persons;
+ }
+
+ /**
+ * Sets the value of the "fax" attribute.
+ *
+ * @param fax
+ * The value of the "fax" attribute.
+ */
+ public void setFax(String fax) {
+ this.fax = fax;
+ }
+ /**
+ * Sets the value of the "id" attribute.
+ *
+ * @param id
+ * The value of the "id" attribute.
+ */
+ public void setId(int id) {
+ this.id = id;
+ }
+ /**
+ * Sets the value of the "telephone" attribute.
+ *
+ * @param telephone
+ * The value of the "telephone" attribute.
+ */
+ public void setTelephone(String telephone) {
+ this.telephone = telephone;
+ }
+ /**
+ * Sets the value of the "address" attribute.
+ *
+ * @param address
+ * The value of the "address" attribute.
+ */
+ public void setAddress(EmbeddableAddress address) {
+ this.address = address;
+ }
+
+ /**
+ * Sets the value of the "tracking" attribute.
+ *
+ * @param tracking
+ * The value of the "tracking" attribute.
+ */
+ public void setTracking(Tracking tracking) {
+ this.tracking = tracking;
+ }
+
+ /**
+ * Sets the value of the "company" attribute.
+ *
+ * @param company"
+ * The value of the "company" attribute.
+ */
+ public void setCompany(Company company) {
+ this.company = company;
+ }
+
+ /**
+ * Sets the value of the "jobParts" attribute.
+ *
+ * @param jobParts"
+ * The value of the "jobParts" attribute.
+ */
+ public void setJobParts(List jobParts) {
+ this.jobParts = jobParts;
+ }
+
+ /**
+ * Sets the value of the "jobPostingParts" attribute.
+ *
+ * @param jobPostingParts"
+ * The value of the "jobPostingParts" attribute.
+ */
+ public void setJobPostingParts(List jobPostingParts) {
+ this.jobPostingParts = jobPostingParts;
+ }
+
+ /**
+ * Sets the value of the "name" attribute.
+ *
+ * @param name"
+ * The value of the "name" attribute.
+ */
+ public void setName(Multilingual name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the value of the "persons" attribute.
+ *
+ * @param persons"
+ * The value of the "persons" attribute.
+ */
+ public void setPersons(List persons) {
+ this.persons = persons;
+ }
}
\ No newline at end of file
diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/Category.java b/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/Category.java
index 0bcd2f4690..4326619640 100644
--- a/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/Category.java
+++ b/modules/org.restlet.test/src/org/restlet/test/ext/odata/deepexpand/model/Category.java
@@ -33,6 +33,8 @@
package org.restlet.test.ext.odata.deepexpand.model;
+
+import java.util.ArrayList;
import java.util.List;
import org.restlet.test.ext.odata.deepexpand.model.Category;
@@ -41,31 +43,21 @@
import org.restlet.test.ext.odata.deepexpand.model.Registration;
/**
- * Generated by the generator tool for the OData extension for the Restlet
- * framework.
- *
- * @see Metadata
- * of the target OData service
- *
- */
+* Generated by the generator tool for the OData extension for the Restlet framework.
+*
+* @see Metadata of the target OData service
+*
+*/
public class Category {
private int id;
-
private String path;
-
private Tracking tracking;
-
- private List childCategories;
-
- private List companies;
-
+ private List childCategories = new ArrayList();
+ private List companies = new ArrayList();
private Multilingual name;
-
private Category parentCategory;
-
- private List preferredByRegistrations;
+ private List preferredByRegistrations = new ArrayList