[VXQUERY-180] REST Server implementation - Implemented REST API - Altered CLI to use REST API - Migrated XTests to use REST API
details: - Implemented the REST Server to start through the cluster controller application. - CLI now calls the REST API (remote if given, local one else) to execute queries. - Migrated XTests to use the REST API to run queries related to tests Project: http://git-wip-us.apache.org/repos/asf/vxquery/repo Commit: http://git-wip-us.apache.org/repos/asf/vxquery/commit/f2e5fd90 Tree: http://git-wip-us.apache.org/repos/asf/vxquery/tree/f2e5fd90 Diff: http://git-wip-us.apache.org/repos/asf/vxquery/diff/f2e5fd90 Branch: refs/heads/master Commit: f2e5fd90f5c9788d0cdc5e381e70e5428f5722e6 Parents: 4a38f67 Author: erandiganepola <[email protected]> Authored: Sun Jun 4 14:32:29 2017 +0530 Committer: Erandi Ganepola <[email protected]> Committed: Fri Aug 25 06:55:23 2017 +0530 ---------------------------------------------------------------------- pom.xml | 15 + src/site/apt/user_query.apt | 35 +- vxquery-cli/pom.xml | 64 +-- .../java/org/apache/vxquery/cli/VXQuery.java | 576 +++++++++---------- vxquery-cli/src/site/markdown/index.md | 116 ++++ vxquery-cli/src/site/site.xml | 57 +- .../exceptions/VXQueryRuntimeException.java | 34 ++ .../VXQueryServletRuntimeException.java | 34 ++ .../metadata/VXQueryMetadataProvider.java | 1 - vxquery-rest/pom.xml | 56 ++ .../apache/vxquery/app/VXQueryApplication.java | 179 ++++++ .../vxquery/app/util/LocalClusterUtil.java | 187 ++++++ .../org/apache/vxquery/app/util/RestUtils.java | 200 +++++++ .../java/org/apache/vxquery/rest/Constants.java | 71 +++ .../org/apache/vxquery/rest/RestServer.java | 84 +++ .../vxquery/rest/request/QueryRequest.java | 165 ++++++ .../rest/request/QueryResultRequest.java | 57 ++ .../vxquery/rest/response/APIResponse.java | 87 +++ .../rest/response/AsyncQueryResponse.java | 47 ++ .../org/apache/vxquery/rest/response/Error.java | 101 ++++ .../vxquery/rest/response/ErrorResponse.java | 56 ++ .../apache/vxquery/rest/response/Metrics.java | 42 ++ .../vxquery/rest/response/QueryResponse.java | 88 +++ .../rest/response/QueryResultResponse.java | 49 ++ .../rest/response/SyncQueryResponse.java | 34 ++ .../vxquery/rest/service/HyracksJobContext.java | 53 ++ .../org/apache/vxquery/rest/service/State.java | 30 + .../org/apache/vxquery/rest/service/Status.java | 51 ++ .../vxquery/rest/service/VXQueryConfig.java | 100 ++++ .../vxquery/rest/service/VXQueryService.java | 482 ++++++++++++++++ .../vxquery/rest/servlet/QueryAPIServlet.java | 139 +++++ .../rest/servlet/QueryResultAPIServlet.java | 67 +++ .../vxquery/rest/servlet/RestAPIServlet.java | 168 ++++++ vxquery-rest/src/site/markdown/index.md | 249 ++++++++ vxquery-rest/src/site/markdown/specification.md | 102 ++++ vxquery-rest/src/site/site.xml | 53 ++ .../vxquery/rest/AbstractRestServerTest.java | 225 ++++++++ .../apache/vxquery/rest/ErrorResponseTest.java | 200 +++++++ .../vxquery/rest/SuccessAsyncResponseTest.java | 289 ++++++++++ .../vxquery/rest/SuccessSyncResponseTest.java | 215 +++++++ .../src/test/resources/vxquery.properties | 30 + vxquery-server/pom.xml | 10 +- vxquery-xtest/pom.xml | 6 + .../apache/vxquery/xtest/TestClusterUtil.java | 81 +-- .../org/apache/vxquery/xtest/TestRunner.java | 239 +++----- .../java/org/apache/vxquery/xtest/XTest.java | 13 +- .../vxquery/xtest/AbstractXQueryTest.java | 9 +- .../GhcndRecords/Partition-2/q03_records-1.txt | 3 + .../GhcndRecords/Partition-2/q03_records-2.txt | 3 + .../GhcndRecords/Partition-2/q03_records-3.txt | 3 + .../GhcndRecords/Partition-2/q03_records-4.txt | 3 + .../GhcndRecords/Partition-2/q03_records-5.txt | 3 + .../GhcndRecords/Partition-4/q03_records-1.txt | 3 + .../GhcndRecords/Partition-4/q03_records-2.txt | 3 + .../GhcndRecords/Partition-4/q03_records-3.txt | 3 + .../GhcndRecords/Partition-4/q03_records-4.txt | 3 + .../GhcndRecords/Partition-4/q03_records-5.txt | 3 + .../Json/Parser/Partition-1/q15_parser-1.txt | 3 + .../Json/Parser/Partition-1/q15_parser-2.txt | 3 + .../Json/Parser/Partition-1/q15_parser-3.txt | 3 + .../Json/Parser/Partition-1/q15_parser-4.txt | 3 + .../Json/Parser/Partition-1/q15_parser-5.txt | 3 + .../Json/Parser/Partition-2/q15_parser-1.txt | 3 + .../Json/Parser/Partition-2/q15_parser-2.txt | 3 + .../Json/Parser/Partition-2/q15_parser-3.txt | 3 + .../Json/Parser/Partition-2/q15_parser-4.txt | 3 + .../Json/Parser/Partition-2/q15_parser-5.txt | 3 + .../Json/Parser/Partition-4/q15_parser-1.txt | 3 + .../Json/Parser/Partition-4/q15_parser-2.txt | 3 + .../Json/Parser/Partition-4/q15_parser-3.txt | 3 + .../Json/Parser/Partition-4/q15_parser-4.txt | 3 + .../Json/Parser/Partition-4/q15_parser-5.txt | 3 + .../test/resources/cat/JsonParserQueries.xml | 19 +- 73 files changed, 4714 insertions(+), 626 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 5f03a49..7e298c5 100644 --- a/pom.xml +++ b/pom.xml @@ -251,6 +251,18 @@ <dependency> <groupId>org.apache.hyracks</groupId> + <artifactId>hyracks-http</artifactId> + <version>${hyracks.fullstack.version}</version> + </dependency> + + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-all</artifactId> + <version>4.1.6.Final</version> + </dependency> + + <dependency> + <groupId>org.apache.hyracks</groupId> <artifactId>algebricks-compiler</artifactId> <version>${hyracks.version}</version> </dependency> @@ -670,6 +682,8 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <hyracks.version>0.2.17-incubating</hyracks.version> + <hyracks.fullstack.version>0.3.1</hyracks.fullstack.version> <hyracks.version>0.3.0</hyracks.version> <apache-rat-plugin.version>0.11</apache-rat-plugin.version> </properties> @@ -680,5 +694,6 @@ <module>vxquery-cli</module> <module>vxquery-xtest</module> <module>vxquery-benchmark</module> + <module>vxquery-rest</module> </modules> </project> http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/src/site/apt/user_query.apt ---------------------------------------------------------------------- diff --git a/src/site/apt/user_query.apt b/src/site/apt/user_query.apt index c5132c3..f4d0dd5 100644 --- a/src/site/apt/user_query.apt +++ b/src/site/apt/user_query.apt @@ -35,21 +35,26 @@ vxq "path-to"\test.xq Command line options for all systems. ---------------------------------------- --O N : Optimization Level. Default: Full Optimization --available-processors N : Number of available processors. (default java's available processors) --client-net-ip-address VAL : IP Address of the ClusterController --client-net-port N : Port of the ClusterController (default 1098) --compileonly : Compile the query and stop --frame-size N : Frame size in bytes. (default 65536) --local-node-controllers N : Number of local node controllers (default 1) --repeatexec N : Number of times to repeat execution --showast : Show abstract syntax tree --showoet : Show optimized expression tree --showquery : Show query string --showrp : Show Runtime plan --showtet : Show translated expression tree --timing : Produce timing information --hdfs-conf VAL : The folder containing the HDFS configuration files + -O N : Optimization Level. (default: Full Optimization) + -available-processors N : Number of available processors. (default: java's available processors) + -buffer-size N : Disk read buffer size in bytes. + -compileonly : Compile the query and stop. + -frame-size N : Frame size in bytes. (default: 65,536) + -hdfs-conf VAL : Directory path to Hadoop configuration files + -join-hash-size N : Join hash size in bytes. (default: 67,108,864) + -local-node-controllers N : Number of local node controllers. (default: 1) + -maximum-data-size N : Maximum possible data size in bytes. (default: 150,323,855,000) + -repeatexec N : Number of times to repeat execution. + -rest-ip-address VAL : IP Address of the REST Server. + -rest-port N : Port of REST Server. + -result-file VAL : File path to save the query result. + -showast : Show abstract syntax tree. + -showoet : Show optimized expression tree. + -showquery : Show query string. + -showrp : Show Runtime plan. + -showtet : Show translated expression tree. + -timing : Produce timing information. + -timing-ignore-queries N : Ignore the first X number of quereies. ---------------------------------------- * Java Options http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-cli/pom.xml ---------------------------------------------------------------------- diff --git a/vxquery-cli/pom.xml b/vxquery-cli/pom.xml index 52c32ad..e7ad16a 100644 --- a/vxquery-cli/pom.xml +++ b/vxquery-cli/pom.xml @@ -14,7 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -61,12 +62,6 @@ </execution> </executions> </plugin> - <!-- - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-site-plugin</artifactId> - </plugin> - --> <plugin> <artifactId>maven-antrun-plugin</artifactId> <executions> @@ -82,64 +77,11 @@ <dependencies> <dependency> <groupId>org.apache.vxquery</groupId> - <artifactId>apache-vxquery-core</artifactId> + <artifactId>apache-vxquery-rest</artifactId> <version>0.7-SNAPSHOT</version> - <scope>compile</scope> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>hyracks-api</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>hyracks-client</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>hyracks-control-cc</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>hyracks-control-nc</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>algebricks-common</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>algebricks-core</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>hyracks-control-common</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>hyracks-dataflow-std</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>hyracks-hdfs-core</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.hyracks</groupId> - <artifactId>hyracks-hdfs-2.x</artifactId> </dependency> </dependencies> - - <reporting> <plugins> <plugin> http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-cli/src/main/java/org/apache/vxquery/cli/VXQuery.java ---------------------------------------------------------------------- diff --git a/vxquery-cli/src/main/java/org/apache/vxquery/cli/VXQuery.java b/vxquery-cli/src/main/java/org/apache/vxquery/cli/VXQuery.java index 25ff9c4..23d5eaa 100644 --- a/vxquery-cli/src/main/java/org/apache/vxquery/cli/VXQuery.java +++ b/vxquery-cli/src/main/java/org/apache/vxquery/cli/VXQuery.java @@ -14,73 +14,57 @@ */ package org.apache.vxquery.cli; -import java.io.ByteArrayOutputStream; +import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_JSON; + import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.StringReader; -import java.net.InetAddress; -import java.nio.file.Files; +import java.io.PrintStream; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.logging.LogManager; + +import javax.xml.bind.JAXBException; import org.apache.commons.io.FileUtils; -import org.apache.hyracks.api.client.HyracksConnection; -import org.apache.hyracks.api.client.IHyracksClientConnection; -import org.apache.hyracks.api.client.NodeControllerInfo; -import org.apache.hyracks.api.comm.IFrame; -import org.apache.hyracks.api.comm.IFrameTupleAccessor; -import org.apache.hyracks.api.comm.VSizeFrame; -import org.apache.hyracks.api.dataset.IHyracksDataset; -import org.apache.hyracks.api.dataset.IHyracksDatasetReader; -import org.apache.hyracks.api.dataset.ResultSetId; -import org.apache.hyracks.api.job.JobFlag; -import org.apache.hyracks.api.job.JobId; -import org.apache.hyracks.api.job.JobSpecification; -import org.apache.hyracks.client.dataset.HyracksDataset; -import org.apache.hyracks.control.cc.ClusterControllerService; -import org.apache.hyracks.control.common.controllers.CCConfig; -import org.apache.hyracks.control.common.controllers.NCConfig; -import org.apache.hyracks.control.nc.NodeControllerService; -import org.apache.hyracks.control.nc.resources.memory.FrameManager; -import org.apache.hyracks.dataflow.common.comm.io.ResultFrameTupleAccessor; -import org.apache.vxquery.compiler.CompilerControlBlock; -import org.apache.vxquery.compiler.algebricks.VXQueryGlobalDataFactory; -import org.apache.vxquery.context.DynamicContext; -import org.apache.vxquery.context.DynamicContextImpl; -import org.apache.vxquery.context.RootStaticContextImpl; -import org.apache.vxquery.context.StaticContextImpl; -import org.apache.vxquery.exceptions.SystemException; -import org.apache.vxquery.result.ResultUtils; -import org.apache.vxquery.xmlquery.query.Module; -import org.apache.vxquery.xmlquery.query.VXQueryCompilationListener; -import org.apache.vxquery.xmlquery.query.XMLQueryCompiler; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.utils.HttpClientUtils; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.vxquery.app.util.LocalClusterUtil; +import org.apache.vxquery.app.util.RestUtils; +import org.apache.vxquery.rest.request.QueryRequest; +import org.apache.vxquery.rest.response.AsyncQueryResponse; +import org.apache.vxquery.rest.response.Error; +import org.apache.vxquery.rest.response.ErrorResponse; +import org.apache.vxquery.rest.response.Metrics; +import org.apache.vxquery.rest.response.SyncQueryResponse; +import org.apache.vxquery.rest.service.VXQueryConfig; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; +/** + * CLI for VXQuery. This class is using the REST API to execute statements given by the user. + * + * @author Erandi Ganepola + */ public class VXQuery { + private final CmdLineOptions opts; - private final CmdLineOptions indexOpts; - - private ClusterControllerService cc; - private NodeControllerService[] ncs; - private IHyracksClientConnection hcc; - private IHyracksDataset hds; - private List<String> collectionList; - private ResultSetId resultSetId; - private static List<String> timingMessages = new ArrayList<>(); - private static long sumTiming; - private static long sumSquaredTiming; - private static long minTiming = Long.MAX_VALUE; - private static long maxTiming = Long.MIN_VALUE; + + private static LocalClusterUtil localClusterUtil; + private String restIpAddress; + private int restPort; + + private static List<Metrics> metricsList = new ArrayList<>(); + private int executionIteration; /** * Constructor to use command line options passed. @@ -90,26 +74,17 @@ public class VXQuery { */ public VXQuery(CmdLineOptions opts) { this.opts = opts; - // The index query returns only the result, without any other information. - this.indexOpts = opts; - indexOpts.showAST = false; - indexOpts.showOET = false; - indexOpts.showQuery = false; - indexOpts.showRP = false; - indexOpts.showTET = false; - indexOpts.timing = false; - indexOpts.compileOnly = false; - this.collectionList = new ArrayList<String>(); } /** * Main method to get command line options and execute query process. * * @param args - * @throws Exception + * command line arguments */ - public static void main(String[] args) throws Exception { - Date start = new Date(); + public static void main(String[] args) { + LogManager.getLogManager().reset(); + final CmdLineOptions opts = new CmdLineOptions(); CmdLineParser parser = new CmdLineParser(opts); @@ -120,243 +95,249 @@ public class VXQuery { parser.printUsage(System.err); return; } - if (opts.arguments.isEmpty()) { + + if (opts.xqFiles.isEmpty()) { parser.printUsage(System.err); return; } - VXQuery vxq = new VXQuery(opts); - vxq.execute(); - // if -timing argument passed, show the starting and ending times - if (opts.timing) { - Date end = new Date(); - timingMessage("Execution time: " + (end.getTime() - start.getTime()) + " ms"); - if (opts.repeatExec > opts.timingIgnoreQueries) { - Double mean = (double) (sumTiming) / (opts.repeatExec - opts.timingIgnoreQueries); - double sd = Math.sqrt(sumSquaredTiming / (opts.repeatExec - opts.timingIgnoreQueries) - mean * mean); - timingMessage("Average execution time: " + mean + " ms"); - timingMessage("Standard deviation: " + String.format("%.4f", sd)); - timingMessage("Coefficient of variation: " + String.format("%.4f", sd / mean)); - timingMessage("Minimum execution time: " + minTiming + " ms"); - timingMessage("Maximum execution time: " + maxTiming + " ms"); - } - System.out.println("Timing Summary:"); - for (String time : timingMessages) { - System.out.println(" " + time); - } - } + VXQuery vxq = new VXQuery(opts); + vxq.execute(opts.xqFiles); } - /** - * Creates a new Hyracks connection with: the client IP address and port provided, if IP address is provided in command line. Otherwise create a new virtual - * cluster with Hyracks nodes. Queries passed are run either way. After running queries, if a virtual cluster has been created, it is shut down. - * - * @throws Exception - */ - private void execute() throws Exception { - System.setProperty("vxquery.buffer_size", Integer.toString(opts.bufferSize)); + private void execute(List<String> xqFiles) { + if (opts.restIpAddress == null) { + System.out.println("No REST Ip address given. Creating a local hyracks cluster"); - if (opts.clientNetIpAddress != null) { - hcc = new HyracksConnection(opts.clientNetIpAddress, opts.clientNetPort); - runQueries(); - } else { - if (!opts.compileOnly) { - startLocalHyracks(); + VXQueryConfig vxqConfig = new VXQueryConfig(); + vxqConfig.setAvailableProcessors(opts.availableProcessors); + vxqConfig.setFrameSize(opts.frameSize); + vxqConfig.setHdfsConf(opts.hdfsConf); + vxqConfig.setJoinHashSize(opts.joinHashSize); + vxqConfig.setMaximumDataSize(opts.maximumDataSize); + + localClusterUtil = new LocalClusterUtil(); + try { + localClusterUtil.init(vxqConfig); + restIpAddress = localClusterUtil.getIpAddress(); + restPort = localClusterUtil.getRestPort(); + } catch (Exception e) { + System.err.println("Unable to start local hyracks cluster due to: " + e.getMessage()); + e.printStackTrace(); + return; } + } else { + restIpAddress = opts.restIpAddress; + restPort = opts.restPort; + } + + System.out.println("Running queries given in: " + Arrays.toString(xqFiles.toArray())); + runQueries(xqFiles); + + if (localClusterUtil != null) { try { - runQueries(); - } finally { - if (!opts.compileOnly) { - stopLocalHyracks(); - } + localClusterUtil.deinit(); + } catch (Exception e) { + System.err.println("Error occurred when stopping local hyracks: " + e.getMessage()); } } } - /** - * Reads the contents of the files passed in the list of arguments to a string. If -showquery argument is passed, output the query as string. Run the query - * for the string. - * - * @throws IOException - * @throws SystemException - * @throws Exception - */ + public void runQueries(List<String> xqFiles) { + for (String xqFile : xqFiles) { + String query; + try { + query = slurp(xqFile); + } catch (IOException e) { + System.err.println(String.format("Error occurred when reading XQuery file %s with message: %s", xqFile, + e.getMessage())); + continue; + } - private void runQueries() throws Exception { - List<String> queries = opts.arguments; - // Run the showIndexes query before executing any target query, to store the index metadata - List<String> queriesIndex = new ArrayList<String>(); - queriesIndex.add("vxquery-xtest/src/test/resources/Queries/XQuery/Indexing/Partition-1/showIndexes.xq"); - OutputStream resultStream = new ByteArrayOutputStream(); - executeQuery(queriesIndex.get(0), 1, resultStream, indexOpts); - ByteArrayOutputStream bos = (ByteArrayOutputStream) resultStream; - String result = new String(bos.toByteArray()); - String[] collections = result.split("\n"); - this.collectionList = Arrays.asList(collections); - executeQueries(queries); - } + System.out.println(); + System.out.println("===================================================="); + System.out.println("\tQuery - '" + xqFile + "'"); + System.out.println("===================================================="); - public void executeQueries(List<String> queries) throws Exception { - for (String query : queries) { - OutputStream resultStream = System.out; - if (opts.resultFile != null) { - resultStream = new FileOutputStream(new File(opts.resultFile)); + QueryRequest request = createQueryRequest(opts, query); + metricsList.clear(); + + for (int i = 0; i < opts.repeatExec; i++) { + System.out.println("**** Repetition : " + (i + 1) + " ****"); + + executionIteration = i; + sendQueryRequest(xqFile, request, this); + } + + if (opts.repeatExec > 1) { + showTimingSummary(); } - executeQuery(query, opts.repeatExec, resultStream, opts); } } - public void executeQuery(String query, int repeatedExecution, OutputStream resultStream, CmdLineOptions options) - throws Exception { - PrintWriter writer = new PrintWriter(resultStream, true); - String qStr = slurp(query); - if (opts.showQuery) { - writer.println(qStr); + private void onSuccess(String xqFile, QueryRequest request, SyncQueryResponse response) { + if (response == null) { + System.err.println(String.format("Unable to execute query %s", request.getStatement())); + return; } - VXQueryCompilationListener listener = new VXQueryCompilationListener(opts.showAST, opts.showTET, opts.showOET, - opts.showRP); - Date start = opts.timing ? new Date() : null; + if (opts.showQuery) { + printField("Query", response.getStatement()); + } - Map<String, NodeControllerInfo> nodeControllerInfos = null; - if (hcc != null) { - nodeControllerInfos = hcc.getNodeControllerInfos(); + if (request.isShowMetrics()) { + String metrics = String.format("Compile Time:\t%d\nElapsed Time:\t%d", + response.getMetrics().getCompileTime(), response.getMetrics().getElapsedTime()); + printField("Metrics", metrics); } - XMLQueryCompiler compiler = new XMLQueryCompiler(listener, nodeControllerInfos, opts.frameSize, - opts.availableProcessors, opts.joinHashSize, opts.maximumDataSize, opts.hdfsConf); - resultSetId = createResultSetId(); - CompilerControlBlock ccb = new CompilerControlBlock(new StaticContextImpl(RootStaticContextImpl.INSTANCE), - resultSetId, null); - compiler.compile(query, new StringReader(qStr), ccb, opts.optimizationLevel, this.collectionList); - // if -timing argument passed, show the starting and ending times - Date end = opts.timing ? new Date() : null; - if (opts.timing) { - timingMessage("Compile time: " + (end.getTime() - start.getTime()) + " ms"); + + if (request.isShowAbstractSyntaxTree()) { + printField("Abstract Syntax Tree", response.getAbstractSyntaxTree()); } - if (opts.compileOnly) { - return; + + if (request.isShowTranslatedExpressionTree()) { + printField("Translated Expression Tree", response.getTranslatedExpressionTree()); } - Module module = compiler.getModule(); - JobSpecification js = module.getHyracksJobSpecification(); - - DynamicContext dCtx = new DynamicContextImpl(module.getModuleContext()); - js.setGlobalJobDataFactory(new VXQueryGlobalDataFactory(dCtx.createFactory())); - - // Repeat execution for number of times provided in -repeatexec argument - for (int i = 0; i < repeatedExecution; ++i) { - start = opts.timing ? new Date() : null; - runJob(js, writer); - // if -timing argument passed, show the starting and ending times - if (opts.timing) { - end = new Date(); - long currentRun = end.getTime() - start.getTime(); - if ((i + 1) > opts.timingIgnoreQueries) { - sumTiming += currentRun; - sumSquaredTiming += currentRun * currentRun; - if (currentRun < minTiming) { - minTiming = currentRun; - } - if (maxTiming < currentRun) { - maxTiming = currentRun; - } - } - timingMessage("Job (" + (i + 1) + ") execution time: " + currentRun + " ms"); - } + if (request.isShowOptimizedExpressionTree()) { + printField("Optimized Expression Tree", response.getOptimizedExpressionTree()); } - } - /** - * Creates a Hyracks dataset, if not already existing with the job frame size, and 1 reader. Allocates a new buffer of size specified in the frame of Hyracks - * node. Creates new dataset reader with the current job ID and result set ID. Outputs the string in buffer for each frame. - * - * @param spec - * JobSpecification object, containing frame size. Current specified job. - * @param writer - * Writer for output of job. - * @throws Exception - */ - private void runJob(JobSpecification spec, PrintWriter writer) throws Exception { - int nReaders = 1; - if (hds == null) { - hds = new HyracksDataset(hcc, spec.getFrameSize(), nReaders); + if (request.isShowRuntimePlan()) { + printField("Runtime Plan", response.getRuntimePlan()); } - JobId jobId = hcc.startJob(spec, EnumSet.of(JobFlag.PROFILE_RUNTIME)); + printField("Results", response.getResults()); - FrameManager resultDisplayFrameMgr = new FrameManager(spec.getFrameSize()); - IFrame frame = new VSizeFrame(resultDisplayFrameMgr); - IHyracksDatasetReader reader = hds.createReader(jobId, resultSetId); - IFrameTupleAccessor frameTupleAccessor = new ResultFrameTupleAccessor(); + if (executionIteration >= opts.timingIgnoreQueries) { + metricsList.add(response.getMetrics()); + } + } - while (reader.read(frame) > 0) { - writer.print(ResultUtils.getStringFromBuffer(frame.getBuffer(), frameTupleAccessor)); - writer.flush(); - frame.getBuffer().clear(); + private void onFailure(String xqFile, ErrorResponse response) { + if (response == null) { + System.err.println(String.format("Unable to execute query in %s", xqFile)); + return; } - hcc.waitForCompletion(jobId); - } + System.err.println(); + System.err.println("------------------------ Errors ---------------------"); - /** - * Create a unique result set id to get the correct query back from the cluster. - * - * @return Result Set id generated with current system time. - */ - protected ResultSetId createResultSetId() { - return new ResultSetId(System.nanoTime()); + Error error = response.getError(); + String errorMsg = String.format("Code:\t %d\nMessage:\t %s", error.getCode(), error.getMessage()); + printField(System.err, String.format("Errors for '%s'", xqFile), errorMsg); } /** - * Start local virtual cluster with cluster controller node and node controller nodes. IP address provided for node controller is localhost. Unassigned ports - * 39000 and 39001 are used for client and cluster port respectively. Creates a new Hyracks connection with the IP address and client ports. + * Submits a query to be executed by the REST API. Will call {@link #onFailure(String, ErrorResponse)} if any error + * occurs when submitting the query. Else will call {@link #onSuccess(String, QueryRequest, SyncQueryResponse)} with + * the {@link AsyncQueryResponse} * - * @throws Exception + * @param xqFile + * .xq file with the query to be executed + * @param request + * {@link QueryRequest} instance to be submitted to REST API + * @param cli + * cli class instance */ - public void startLocalHyracks() throws Exception { - String localAddress = InetAddress.getLocalHost().getHostAddress(); - CCConfig ccConfig = new CCConfig(); - ccConfig.clientNetIpAddress = localAddress; - ccConfig.clientNetPort = 39000; - ccConfig.clusterNetIpAddress = localAddress; - ccConfig.clusterNetPort = 39001; - ccConfig.httpPort = 39002; - ccConfig.profileDumpPeriod = 10000; - cc = new ClusterControllerService(ccConfig); - cc.start(); - - ncs = new NodeControllerService[opts.localNodeControllers]; - for (int i = 0; i < ncs.length; i++) { - NCConfig ncConfig = new NCConfig(); - ncConfig.ccHost = "localhost"; - ncConfig.ccPort = 39001; - ncConfig.clusterNetIPAddress = localAddress; - ncConfig.dataIPAddress = localAddress; - ncConfig.resultIPAddress = localAddress; - ncConfig.nodeId = "nc" + (i + 1); - //TODO: enable index folder as a cli option for on-the-fly indexing queries - ncConfig.ioDevices = Files.createTempDirectory(ncConfig.nodeId).toString(); - ncs[i] = new NodeControllerService(ncConfig); - ncs[i].start(); + private static void sendQueryRequest(String xqFile, QueryRequest request, VXQuery cli) { + URI uri = null; + try { + uri = RestUtils.buildQueryURI(request, cli.restIpAddress, cli.restPort); + } catch (URISyntaxException e) { + System.err.println( + String.format("Unable to build URI to call REST API for query: %s", request.getStatement())); + cli.onFailure(xqFile, null); } - hcc = new HyracksConnection(ccConfig.clientNetIpAddress, ccConfig.clientNetPort); + CloseableHttpClient httpClient = HttpClients.custom().build(); + try { + HttpGet httpGet = new HttpGet(uri); + httpGet.setHeader(HttpHeaders.ACCEPT, CONTENT_TYPE_JSON); + + try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) { + HttpEntity entity = httpResponse.getEntity(); + + String response = RestUtils.readEntity(entity); + if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + cli.onSuccess(xqFile, request, + RestUtils.mapEntity(response, SyncQueryResponse.class, CONTENT_TYPE_JSON)); + } else { + cli.onFailure(xqFile, RestUtils.mapEntity(response, ErrorResponse.class, CONTENT_TYPE_JSON)); + } + } catch (IOException e) { + System.err.println("Error occurred when reading entity: " + e.getMessage()); + cli.onFailure(xqFile, null); + } catch (JAXBException e) { + System.err.println("Error occurred when mapping query response: " + e.getMessage()); + cli.onFailure(xqFile, null); + } + } finally { + HttpClientUtils.closeQuietly(httpClient); + } } /** - * Shuts down the virtual cluster, along with all nodes and node execution, network and queue managers. - * - * @throws Exception + * Once the query in a given .xq file has been executed (with repeated executions as well), this method calculates + * mean, standard deviation, minimum and maximum execution times. */ - public void stopLocalHyracks() throws Exception { - for (int i = 0; i < ncs.length; i++) { - ncs[i].stop(); + private void showTimingSummary() { + double sumTime = 0; + double sumSquaredTime = 0; + long minTime = Long.MAX_VALUE; + long maxTime = Long.MIN_VALUE; + + for (int i = 0; i < metricsList.size(); i++) { + Metrics metrics = metricsList.get(i); + long totalTime = metrics.getCompileTime() + metrics.getElapsedTime(); + + sumTime += totalTime; + sumSquaredTime += totalTime * totalTime; + + if (totalTime < minTime) { + minTime = totalTime; + } + + if (totalTime > maxTime) { + maxTime = totalTime; + } } - cc.stop(); + + double mean = sumTime / (opts.repeatExec - opts.timingIgnoreQueries); + double sd = Math.sqrt(sumSquaredTime / (opts.repeatExec - opts.timingIgnoreQueries) - mean * mean); + + System.out.println(); + System.out.println("\t**** Timing Summary ****"); + System.out.println("----------------------------------------------------"); + System.out.println(String.format("Repetitions:\t%d, Timing Ignored Iterations:\t%d", opts.repeatExec, + opts.timingIgnoreQueries)); + System.out.println("Average execution time:\t" + mean + " ms"); + System.out.println("Standard deviation:\t" + String.format("%.4f", sd)); + System.out.println("Coefficient of variation:\t" + String.format("%.4f", sd / mean)); + System.out.println("Minimum execution time:\t" + minTime + " ms"); + System.out.println("Maximum execution time:\t" + maxTime + " ms"); + System.out.println(); + } + + private static QueryRequest createQueryRequest(CmdLineOptions opts, String query) { + QueryRequest request = new QueryRequest(query); + request.setCompileOnly(opts.compileOnly); + request.setOptimization(opts.optimizationLevel); + request.setFrameSize(opts.frameSize); + request.setRepeatExecutions(opts.repeatExec); + request.setShowMetrics(opts.timing); + request.setShowAbstractSyntaxTree(opts.showAST); + request.setShowTranslatedExpressionTree(opts.showTET); + request.setShowOptimizedExpressionTree(opts.showOET); + request.setShowRuntimePlan(opts.showRP); + request.setAsync(false); + + return request; } /** - * Reads the contents of file given in query into a String. The file is always closed. For XML files UTF-8 encoding is used. + * Reads the contents of file given in query into a String. The file is always closed. For XML files UTF-8 encoding + * is used. * * @param query * The query with filename to be processed @@ -367,46 +348,49 @@ public class VXQuery { return FileUtils.readFileToString(new File(query), "UTF-8"); } - /** - * Save and print out the timing message. - * - * @param message - */ - private static void timingMessage(String message) { - System.out.println(message); - timingMessages.add(message); + private static void printField(PrintStream out, String field, String value) { + out.println(); + field = field + ":"; + out.print(field); + + String[] lines = value.split("\n"); + for (int i = 0; i < lines.length; i++) { + int margin = 4; + if (i != 0) { + margin += field.length(); + } + System.out.print(String.format("%1$" + margin + "s%2$s\n", "", lines[i])); + } + } + + private static void printField(String field, String value) { + printField(System.out, field, value); } /** * Helper class with fields and methods to handle all command line options */ private static class CmdLineOptions { - @Option(name = "-available-processors", usage = "Number of available processors. (default: java's available processors)") - private int availableProcessors = -1; + @Option(name = "-rest-ip-address", usage = "IP Address of the REST Server") + private String restIpAddress = null; - @Option(name = "-client-net-ip-address", usage = "IP Address of the ClusterController.") - private String clientNetIpAddress = null; + @Option(name = "-rest-port", usage = "Port of REST Server") + private int restPort = 8085; - @Option(name = "-client-net-port", usage = "Port of the ClusterController. (default: 1098)") - private int clientNetPort = 1098; + @Option(name = "-compileonly", usage = "Compile the query and stop.") + private boolean compileOnly; - @Option(name = "-local-node-controllers", usage = "Number of local node controllers. (default: 1)") - private int localNodeControllers = 1; + @Option(name = "-O", usage = "Optimization Level. (default: Full Optimization)") + private int optimizationLevel = Integer.MAX_VALUE; @Option(name = "-frame-size", usage = "Frame size in bytes. (default: 65,536)") private int frameSize = 65536; - @Option(name = "-join-hash-size", usage = "Join hash size in bytes. (default: 67,108,864)") - private long joinHashSize = -1; - - @Option(name = "-maximum-data-size", usage = "Maximum possible data size in bytes. (default: 150,323,855,000)") - private long maximumDataSize = -1; - - @Option(name = "-buffer-size", usage = "Disk read buffer size in bytes.") - private int bufferSize = -1; + @Option(name = "-repeatexec", usage = "Number of times to repeat execution.") + private int repeatExec = 1; - @Option(name = "-O", usage = "Optimization Level. (default: Full Optimization)") - private int optimizationLevel = Integer.MAX_VALUE; + @Option(name = "-timing", usage = "Produce timing information.") + private boolean timing; @Option(name = "-showquery", usage = "Show query string.") private boolean showQuery; @@ -423,29 +407,33 @@ public class VXQuery { @Option(name = "-showrp", usage = "Show Runtime plan.") private boolean showRP; - @Option(name = "-compileonly", usage = "Compile the query and stop.") - private boolean compileOnly; + // Optional (Not supported by REST API) parameters. Only used for creating a + // local hyracks cluster + @Option(name = "-join-hash-size", usage = "Join hash size in bytes. (default: 67,108,864)") + private long joinHashSize = -1; - @Option(name = "-repeatexec", usage = "Number of times to repeat execution.") - private int repeatExec = 1; + @Option(name = "-maximum-data-size", usage = "Maximum possible data size in bytes. (default: 150,323,855,000)") + private long maximumDataSize = -1; + + @Option(name = "-buffer-size", usage = "Disk read buffer size in bytes.") + private int bufferSize = -1; @Option(name = "-result-file", usage = "File path to save the query result.") private String resultFile = null; - @Option(name = "-timing", usage = "Produce timing information.") - private boolean timing; - @Option(name = "-timing-ignore-queries", usage = "Ignore the first X number of quereies.") - private int timingIgnoreQueries = 2; - - @Option(name = "-x", usage = "Bind an external variable") - private Map<String, String> bindings = new HashMap<>(); + private int timingIgnoreQueries = 0; @Option(name = "-hdfs-conf", usage = "Directory path to Hadoop configuration files") private String hdfsConf = null; + @Option(name = "-available-processors", usage = "Number of available processors. (default: java's available processors)") + private int availableProcessors = -1; + + @Option(name = "-local-node-controllers", usage = "Number of local node controllers. (default: 1)") + private int localNodeControllers = 1; + @Argument - private List<String> arguments = new ArrayList<>(); + private List<String> xqFiles = new ArrayList<>(); } - -} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-cli/src/site/markdown/index.md ---------------------------------------------------------------------- diff --git a/vxquery-cli/src/site/markdown/index.md b/vxquery-cli/src/site/markdown/index.md new file mode 100644 index 0000000..758c947 --- /dev/null +++ b/vxquery-cli/src/site/markdown/index.md @@ -0,0 +1,116 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> +# VXQuery CLI + +VXQuery CLI is the command line utility which can be used to execute XQueries +with ease. No pre-configuration needs to be done in order to execute an XQuery. + +--- + +## Quick Start + +*** + +### Requirements + +- Apache VXQuery⢠source archive (apache-vxquery-X.Y-source-release.zip) +- JDK >= 1.8 +- Apache Maven >= 3.2 + +*** + +### Installing + +VXQuery CLI comes bundled with the VXQuery source distribution +(apache-vxquery-X.Y-source-release.zip). + +First, run `mvn package`. + +``` +$ unzip apache-vxquery-X.Y-source-release.zip +$ cd apache-vxquery-X.Y +$ mvn package -DskipTests +``` + +**vxquery-cli** binaries are located at `vxquery-cli/target/appassembler/bin`. +There are 2 files in this directory, **vxq** which is the bash executable for unix +based systems and **vxq.bat** for windows systems. Depending on the platform, +suitable executable needs to be selected. + +*** + +### Executing a Query + +#### Put the query into a file + +VXQuery CLI takes a file location as the argument where this file includes the +query(statement) to be executed. Suppose the following query needs to be executed. + +``` +for $x in doc("books.xml")/bookstore/book +where $x/price>30 +order by $x/title +return $x/title +``` +This statement is querying for the book titles in **books.xml** where price of +the book is greater than 30. Also this query asks for the results to be ordered by +*title* as well. Now, create a file (say **test.xq**) and put the above query as +the content. + +**NOTE:** You can replace **books.xml** with any XML file that you have and want +to run a query on. + +#### Execute the query + +We need to invoke the matching executable according to your platform (unix/windows) +inside `vxquery-cli/target/appassembler/bin` directory. To execute the query, run: + +``` +sh ./apache-vxquery-X.Y/vxquery-cli/target/appassembler/bin/vxq path/to/test.xq +``` + +*** + +## Command Line Options + +``` + -O N : Optimization Level. (default: Full Optimization) + -available-processors N : Number of available processors. (default: java's available processors) + -buffer-size N : Disk read buffer size in bytes. + -compileonly : Compile the query and stop. + -frame-size N : Frame size in bytes. (default: 65,536) + -hdfs-conf VAL : Directory path to Hadoop configuration files + -join-hash-size N : Join hash size in bytes. (default: 67,108,864) + -local-node-controllers N : Number of local node controllers. (default: 1) + -maximum-data-size N : Maximum possible data size in bytes. (default: 150,323,855,000) + -repeatexec N : Number of times to repeat execution. + -rest-ip-address VAL : IP Address of the REST Server. + -rest-port N : Port of REST Server. + -result-file VAL : File path to save the query result. + -showast : Show abstract syntax tree. + -showoet : Show optimized expression tree. + -showquery : Show query string. + -showrp : Show Runtime plan. + -showtet : Show translated expression tree. + -timing : Produce timing information. + -timing-ignore-queries N : Ignore the first X number of quereies. +``` + +**NOTE:** Normally, CLI starts a local VXQuery Server to execute the query. But, +if you already have a VXQuery Server running, you can send the query to the +inbuilt *REST Server* running in that server by specifying the **port** and **ip address** +of the REST Server through options `-rest-ip-address` and `-rest-port`. http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-cli/src/site/site.xml ---------------------------------------------------------------------- diff --git a/vxquery-cli/src/site/site.xml b/vxquery-cli/src/site/site.xml index 4d35a0f..8b3198d 100644 --- a/vxquery-cli/src/site/site.xml +++ b/vxquery-cli/src/site/site.xml @@ -15,34 +15,39 @@ See the License for the specific language governing permissions and limitations under the License. --> <project name="VXQuery"> - <bannerLeft> - <name>VXQuery</name> - <src>../images/VXQuery.png</src> - <href>../index.html</href> - </bannerLeft> + <bannerLeft> + <name>VXQuery</name> + <src>../images/VXQuery.png</src> + <href>../index.html</href> + </bannerLeft> - <bannerRight> - <name>Apache Software Foundation</name> - <src>../images/asf_logo_wide.png</src> - <href>http://www.apache.org/</href> - </bannerRight> + <bannerRight> + <name>Apache Software Foundation</name> + <src>../images/asf_logo_wide.png</src> + <href>http://www.apache.org/</href> + </bannerRight> - <skin> - <groupId>org.apache.maven.skins</groupId> - <artifactId>maven-fluido-skin</artifactId> - <version>1.5</version> - </skin> + <skin> + <groupId>org.apache.maven.skins</groupId> + <artifactId>maven-fluido-skin</artifactId> + <version>1.5</version> + </skin> - <body> - <menu ref="reports"/> - <footer><![CDATA[ - <div class="row-fluid">Apache VXQuery, VXQuery, Apache, the Apache - feather logo, and the Apache VXQuery project logo are either - registered trademarks or trademarks of The Apache Software - Foundation in the United States and other countries. - All other marks mentioned may be trademarks or registered - trademarks of their respective owners.</div> - ]]></footer> - </body> + <body> + <menu name="VXQuery CLI"> + <item name="Overview" href="index.html"/> + </menu> + + <menu ref="reports"/> + <footer><![CDATA[ + <div class="row-fluid">Apache VXQuery, VXQuery, Apache, the Apache + feather logo, and the Apache VXQuery project logo are either + registered trademarks or trademarks of The Apache Software + Foundation in the United States and other countries. + All other marks mentioned may be trademarks or registered + trademarks of their respective owners. + </div>]]> + </footer> + </body> </project> http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-core/src/main/java/org/apache/vxquery/exceptions/VXQueryRuntimeException.java ---------------------------------------------------------------------- diff --git a/vxquery-core/src/main/java/org/apache/vxquery/exceptions/VXQueryRuntimeException.java b/vxquery-core/src/main/java/org/apache/vxquery/exceptions/VXQueryRuntimeException.java new file mode 100644 index 0000000..7f748b7 --- /dev/null +++ b/vxquery-core/src/main/java/org/apache/vxquery/exceptions/VXQueryRuntimeException.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.vxquery.exceptions; + +/** + * A runtime exception to be thrown by the VXQuery and related classes of the rest server + * + * @author Erandi Ganepola + */ +public class VXQueryRuntimeException extends RuntimeException { + + public VXQueryRuntimeException(String message) { + super(message); + } + + public VXQueryRuntimeException(String message, Throwable cause) { + super(message, cause); + } +} http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-core/src/main/java/org/apache/vxquery/exceptions/VXQueryServletRuntimeException.java ---------------------------------------------------------------------- diff --git a/vxquery-core/src/main/java/org/apache/vxquery/exceptions/VXQueryServletRuntimeException.java b/vxquery-core/src/main/java/org/apache/vxquery/exceptions/VXQueryServletRuntimeException.java new file mode 100644 index 0000000..f05cd6f --- /dev/null +++ b/vxquery-core/src/main/java/org/apache/vxquery/exceptions/VXQueryServletRuntimeException.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.vxquery.exceptions; + +/** + * A runtime exception class to be used to be thrown when runtime errors occur within servlets. + * + * @author Erandi Ganepola + */ +public class VXQueryServletRuntimeException extends VXQueryRuntimeException { + + public VXQueryServletRuntimeException(String message) { + super(message); + } + + public VXQueryServletRuntimeException(String message, Throwable cause) { + super(message, cause); + } +} http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-core/src/main/java/org/apache/vxquery/metadata/VXQueryMetadataProvider.java ---------------------------------------------------------------------- diff --git a/vxquery-core/src/main/java/org/apache/vxquery/metadata/VXQueryMetadataProvider.java b/vxquery-core/src/main/java/org/apache/vxquery/metadata/VXQueryMetadataProvider.java index 5bb9d1a..1527059 100644 --- a/vxquery-core/src/main/java/org/apache/vxquery/metadata/VXQueryMetadataProvider.java +++ b/vxquery-core/src/main/java/org/apache/vxquery/metadata/VXQueryMetadataProvider.java @@ -285,5 +285,4 @@ public class VXQueryMetadataProvider implements IMetadataProvider<String, String } return indexExists; } - } http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/pom.xml ---------------------------------------------------------------------- diff --git a/vxquery-rest/pom.xml b/vxquery-rest/pom.xml new file mode 100644 index 0000000..052132f --- /dev/null +++ b/vxquery-rest/pom.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>apache-vxquery</artifactId> + <groupId>org.apache.vxquery</groupId> + <version>0.7-SNAPSHOT</version> + </parent> + + <modelVersion>4.0.0</modelVersion> + <packaging>jar</packaging> + <name>VXQuery REST Server</name> + <description>Apache VXQuery REST Server</description> + + <artifactId>apache-vxquery-rest</artifactId> + + <dependencies> + <dependency> + <groupId>org.apache.vxquery</groupId> + <artifactId>apache-vxquery-core</artifactId> + <version>0.7-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.hyracks</groupId> + <artifactId>hyracks-client</artifactId> + </dependency> + <dependency> + <groupId>org.apache.hyracks</groupId> + <artifactId>hyracks-http</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/main/java/org/apache/vxquery/app/VXQueryApplication.java ---------------------------------------------------------------------- diff --git a/vxquery-rest/src/main/java/org/apache/vxquery/app/VXQueryApplication.java b/vxquery-rest/src/main/java/org/apache/vxquery/app/VXQueryApplication.java new file mode 100644 index 0000000..f5e0165 --- /dev/null +++ b/vxquery-rest/src/main/java/org/apache/vxquery/app/VXQueryApplication.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.vxquery.app; + +import static org.apache.vxquery.rest.Constants.Properties.AVAILABLE_PROCESSORS; +import static org.apache.vxquery.rest.Constants.Properties.HDFS_CONFIG; +import static org.apache.vxquery.rest.Constants.Properties.JOIN_HASH_SIZE; +import static org.apache.vxquery.rest.Constants.Properties.MAXIMUM_DATA_SIZE; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.hyracks.api.application.ICCApplicationContext; +import org.apache.hyracks.api.application.ICCApplicationEntryPoint; +import org.apache.hyracks.api.client.ClusterControllerInfo; +import org.apache.vxquery.exceptions.VXQueryRuntimeException; +import org.apache.vxquery.rest.RestServer; +import org.apache.vxquery.rest.service.VXQueryConfig; +import org.apache.vxquery.rest.service.VXQueryService; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.Option; + +/** + * Main class responsible for starting the {@link RestServer} and + * {@link VXQueryService} classes. + * + * @author Erandi Ganepola + */ +public class VXQueryApplication implements ICCApplicationEntryPoint { + + private static final Logger LOGGER = Logger.getLogger(VXQueryApplication.class.getName()); + + private VXQueryService vxQueryService; + private RestServer restServer; + + @Override + public void start(ICCApplicationContext ccAppCtx, String[] args) throws Exception { + AppArgs appArgs = new AppArgs(); + if (args != null) { + CmdLineParser parser = new CmdLineParser(appArgs); + try { + parser.parseArgument(args); + } catch (Exception e) { + parser.printUsage(System.err); + throw new VXQueryRuntimeException("Unable to parse app arguments", e); + } + } + + VXQueryConfig config = + loadConfiguration(ccAppCtx.getCCContext().getClusterControllerInfo(), appArgs.getVxqueryConfig()); + vxQueryService = new VXQueryService(config); + restServer = new RestServer(vxQueryService, appArgs.getRestPort()); + } + + public synchronized void stop() { + try { + LOGGER.log(Level.INFO, "Stopping REST server"); + restServer.stop(); + + LOGGER.log(Level.INFO, "Stopping VXQueryService"); + vxQueryService.stop(); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error occurred when stopping the application", e); + } + } + + @Override + public void startupCompleted() throws Exception { + try { + LOGGER.log(Level.INFO, "Starting VXQueryService"); + vxQueryService.start(); + LOGGER.log(Level.INFO, "VXQueryService started successfully"); + + LOGGER.log(Level.INFO, "Starting REST server"); + restServer.start(); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error occurred when starting application", e); + stop(); + throw new VXQueryRuntimeException("Error occurred when starting application", e); + } + } + + /** + * Loads properties from + * + * <pre> + * -appConfig foo/bar.properties + * </pre> + * + * file if specified in the app arguments. + * + * @param clusterControllerInfo + * cluster controller information + * @param propertiesFile + * vxquery configuration properties file, given by + * + * <pre> + * -appConfig + * </pre> + * + * option in app argument + * @return A new {@link VXQueryConfig} instance with either default properties + * or properties loaded from the properties file given. + */ + private VXQueryConfig loadConfiguration(ClusterControllerInfo clusterControllerInfo, String propertiesFile) { + VXQueryConfig vxqConfig = new VXQueryConfig(); + if (propertiesFile != null) { + try (InputStream in = new FileInputStream(propertiesFile)) { + System.getProperties().load(in); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, + String.format("Error occurred when loading properties file %s", propertiesFile), e); + } + } + + vxqConfig.setAvailableProcessors(Integer.getInteger(AVAILABLE_PROCESSORS, 1)); + vxqConfig.setJoinHashSize(Long.getLong(JOIN_HASH_SIZE, -1)); + vxqConfig.setHdfsConf(System.getProperty(HDFS_CONFIG)); + vxqConfig.setMaximumDataSize(Long.getLong(MAXIMUM_DATA_SIZE, -1)); + + vxqConfig.setHyracksClientIp(clusterControllerInfo.getClientNetAddress()); + vxqConfig.setHyracksClientPort(clusterControllerInfo.getClientNetPort()); + + return vxqConfig; + } + + public VXQueryService getVxQueryService() { + return vxQueryService; + } + + public RestServer getRestServer() { + return restServer; + } + + /** + * Application Arguments bean class + */ + private class AppArgs { + @Option(name = "-restPort", usage = "The port on which REST server starts") + private int restPort = 8080; + + @Option(name = "-appConfig", usage = "Properties file location which includes VXQueryService Application additional configuration") + private String vxqueryConfig = null; + + public String getVxqueryConfig() { + return vxqueryConfig; + } + + public void setVxqueryConfig(String vxqueryConfig) { + this.vxqueryConfig = vxqueryConfig; + } + + public int getRestPort() { + return restPort; + } + + public void setRestPort(int restPort) { + this.restPort = restPort; + } + } +} http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/main/java/org/apache/vxquery/app/util/LocalClusterUtil.java ---------------------------------------------------------------------- diff --git a/vxquery-rest/src/main/java/org/apache/vxquery/app/util/LocalClusterUtil.java b/vxquery-rest/src/main/java/org/apache/vxquery/app/util/LocalClusterUtil.java new file mode 100644 index 0000000..9b18745 --- /dev/null +++ b/vxquery-rest/src/main/java/org/apache/vxquery/app/util/LocalClusterUtil.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.vxquery.app.util; + +import static org.apache.vxquery.rest.Constants.Properties.AVAILABLE_PROCESSORS; +import static org.apache.vxquery.rest.Constants.Properties.HDFS_CONFIG; +import static org.apache.vxquery.rest.Constants.Properties.JOIN_HASH_SIZE; +import static org.apache.vxquery.rest.Constants.Properties.MAXIMUM_DATA_SIZE; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.util.Arrays; + +import org.apache.hyracks.api.client.HyracksConnection; +import org.apache.hyracks.api.client.IHyracksClientConnection; +import org.apache.hyracks.api.dataset.IHyracksDataset; +import org.apache.hyracks.client.dataset.HyracksDataset; +import org.apache.hyracks.control.cc.ClusterControllerService; +import org.apache.hyracks.control.common.controllers.CCConfig; +import org.apache.hyracks.control.common.controllers.NCConfig; +import org.apache.hyracks.control.nc.NodeControllerService; +import org.apache.vxquery.app.VXQueryApplication; +import org.apache.vxquery.rest.service.VXQueryConfig; +import org.apache.vxquery.rest.service.VXQueryService; + +/** + * A utility class to start the a local hyracks cluster. + * + * @author Preston Carman + */ +public class LocalClusterUtil { + /* + * Start local virtual cluster with cluster controller node and node controller + * nodes. IP address provided for node controller is localhost. Unassigned ports + * 39000 and 39001 are used for client and cluster port respectively. + */ + public static final int DEFAULT_HYRACKS_CC_CLIENT_PORT = 39000; + public static final int DEFAULT_HYRACKS_CC_CLUSTER_PORT = 39001; + public static final int DEFAULT_HYRACKS_CC_HTTP_PORT = 39002; + public static final int DEFAULT_VXQUERY_REST_PORT = 39003; + + // TODO review variable scope after XTest is updated to use the REST service. + public ClusterControllerService clusterControllerService; + public NodeControllerService nodeControllerSerivce; + public IHyracksClientConnection hcc; + public IHyracksDataset hds; + public VXQueryService vxQueryService; + + public void init(VXQueryConfig config) throws Exception { + // Following properties are needed by the app to setup + System.setProperty(AVAILABLE_PROCESSORS, String.valueOf(config.getAvailableProcessors())); + System.setProperty(JOIN_HASH_SIZE, String.valueOf(config.getJoinHashSize())); + System.setProperty(MAXIMUM_DATA_SIZE, String.valueOf(config.getMaximumDataSize())); + if (config.getHdfsConf() != null) { + System.setProperty(HDFS_CONFIG, config.getHdfsConf()); + } + + // Cluster controller + CCConfig ccConfig = createCCConfig(); + clusterControllerService = new ClusterControllerService(ccConfig); + clusterControllerService.start(); + + hcc = new HyracksConnection(ccConfig.clientNetIpAddress, ccConfig.clientNetPort); + hds = new HyracksDataset(hcc, config.getFrameSize(), config.getAvailableProcessors()); + + // Node controller + NCConfig ncConfig = createNCConfig(); + nodeControllerSerivce = new NodeControllerService(ncConfig); + nodeControllerSerivce.start(); + + hcc = new HyracksConnection(ccConfig.clientNetIpAddress, ccConfig.clientNetPort); + + // REST controller + config.setHyracksClientIp(ccConfig.clientNetIpAddress); + config.setHyracksClientPort(ccConfig.clientNetPort); + vxQueryService = new VXQueryService(config); + vxQueryService.start(); + } + + protected CCConfig createCCConfig() throws IOException { + String localAddress = getIpAddress(); + CCConfig ccConfig = new CCConfig(); + ccConfig.clientNetIpAddress = localAddress; + ccConfig.clientNetPort = DEFAULT_HYRACKS_CC_CLIENT_PORT; + ccConfig.clusterNetIpAddress = localAddress; + ccConfig.clusterNetPort = DEFAULT_HYRACKS_CC_CLUSTER_PORT; + ccConfig.httpPort = DEFAULT_HYRACKS_CC_HTTP_PORT; + ccConfig.profileDumpPeriod = 10000; + ccConfig.appCCMainClass = VXQueryApplication.class.getName(); + ccConfig.appArgs = Arrays.asList("-restPort", String.valueOf(DEFAULT_VXQUERY_REST_PORT)); + + return ccConfig; + } + + protected NCConfig createNCConfig() throws IOException { + String localAddress = getIpAddress(); + NCConfig ncConfig = new NCConfig(); + ncConfig.ccHost = "localhost"; + ncConfig.ccPort = DEFAULT_HYRACKS_CC_CLUSTER_PORT; + ncConfig.clusterNetIPAddress = localAddress; + ncConfig.dataIPAddress = localAddress; + ncConfig.resultIPAddress = localAddress; + ncConfig.nodeId = "test_node"; + ncConfig.ioDevices = Files.createTempDirectory(ncConfig.nodeId).toString(); + return ncConfig; + } + + public IHyracksClientConnection getHyracksClientConnection() { + return hcc; + } + + public VXQueryService getVxQueryService() { + return vxQueryService; + } + + public void deinit() throws Exception { + vxQueryService.stop(); + nodeControllerSerivce.stop(); + clusterControllerService.stop(); + } + + public static void main(String[] args) { + LocalClusterUtil localClusterUtil = new LocalClusterUtil(); + VXQueryConfig config = new VXQueryConfig(); + run(localClusterUtil, config); + } + + protected static void run(final LocalClusterUtil localClusterUtil, VXQueryConfig config) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + try { + localClusterUtil.deinit(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + try { + localClusterUtil.init(config); + while (true) { + Thread.sleep(10000); + } + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + public String getIpAddress() throws UnknownHostException { + return InetAddress.getLocalHost().getHostAddress(); + } + + public int getRestPort() { + return DEFAULT_VXQUERY_REST_PORT; + } + + @Deprecated + public IHyracksClientConnection getConnection() { + return hcc; + } + + @Deprecated + public IHyracksDataset getDataset() { + return hds; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/main/java/org/apache/vxquery/app/util/RestUtils.java ---------------------------------------------------------------------- diff --git a/vxquery-rest/src/main/java/org/apache/vxquery/app/util/RestUtils.java b/vxquery-rest/src/main/java/org/apache/vxquery/app/util/RestUtils.java new file mode 100644 index 0000000..fe91836 --- /dev/null +++ b/vxquery-rest/src/main/java/org/apache/vxquery/app/util/RestUtils.java @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.vxquery.app.util; + +import static org.apache.vxquery.rest.Constants.MODE_ASYNC; +import static org.apache.vxquery.rest.Constants.MODE_SYNC; +import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_JSON; +import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_XML; +import static org.apache.vxquery.rest.Constants.Parameters.COMPILE_ONLY; +import static org.apache.vxquery.rest.Constants.Parameters.FRAME_SIZE; +import static org.apache.vxquery.rest.Constants.Parameters.METRICS; +import static org.apache.vxquery.rest.Constants.Parameters.MODE; +import static org.apache.vxquery.rest.Constants.Parameters.OPTIMIZATION; +import static org.apache.vxquery.rest.Constants.Parameters.REPEAT_EXECUTIONS; +import static org.apache.vxquery.rest.Constants.Parameters.SHOW_AST; +import static org.apache.vxquery.rest.Constants.Parameters.SHOW_OET; +import static org.apache.vxquery.rest.Constants.Parameters.SHOW_RP; +import static org.apache.vxquery.rest.Constants.Parameters.SHOW_TET; +import static org.apache.vxquery.rest.Constants.Parameters.STATEMENT; +import static org.apache.vxquery.rest.Constants.URLs.QUERY_ENDPOINT; +import static org.apache.vxquery.rest.Constants.URLs.QUERY_RESULT_ENDPOINT; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.apache.htrace.fasterxml.jackson.databind.ObjectMapper; +import org.apache.http.HttpEntity; +import org.apache.http.client.utils.URIBuilder; +import org.apache.vxquery.rest.request.QueryRequest; +import org.apache.vxquery.rest.request.QueryResultRequest; + +/** + * A set of utility methods used by the REST related tasks + * + * @author Erandi Ganepola + */ +public class RestUtils { + + private RestUtils() { + } + + /** + * Builds the {@link URI} once the {@link QueryRequest} is given. Only the + * parameters given (different from the default values) are put in the + * {@link URI} + * + * @param request + * {@link QueryRequest} to be converted to a {@link URI} + * @param restIpAddress + * Ip address of the REST server + * @param restPort + * port of the REST server + * @return generated {@link URI} + * @throws URISyntaxException + */ + public static URI buildQueryURI(QueryRequest request, String restIpAddress, int restPort) + throws URISyntaxException { + URIBuilder builder = + new URIBuilder().setScheme("http").setHost(restIpAddress).setPort(restPort).setPath(QUERY_ENDPOINT); + + if (request.getStatement() != null) { + builder.addParameter(STATEMENT, request.getStatement()); + } + if (request.isCompileOnly()) { + builder.addParameter(COMPILE_ONLY, String.valueOf(request.isCompileOnly())); + } + if (request.getOptimization() != QueryRequest.DEFAULT_OPTIMIZATION) { + builder.addParameter(OPTIMIZATION, String.valueOf(request.getOptimization())); + } + if (request.getFrameSize() != QueryRequest.DEFAULT_FRAMESIZE) { + builder.addParameter(FRAME_SIZE, String.valueOf(request.getFrameSize())); + } + if (request.getRepeatExecutions() != 1) { + builder.addParameter(REPEAT_EXECUTIONS, String.valueOf(request.getRepeatExecutions())); + } + if (request.isShowMetrics()) { + builder.addParameter(METRICS, String.valueOf(request.isShowMetrics())); + } + if (request.isShowAbstractSyntaxTree()) { + builder.addParameter(SHOW_AST, String.valueOf(request.isShowAbstractSyntaxTree())); + } + if (request.isShowTranslatedExpressionTree()) { + builder.addParameter(SHOW_TET, String.valueOf(request.isShowTranslatedExpressionTree())); + } + if (request.isShowOptimizedExpressionTree()) { + builder.addParameter(SHOW_OET, String.valueOf(request.isShowOptimizedExpressionTree())); + } + if (request.isShowRuntimePlan()) { + builder.addParameter(SHOW_RP, String.valueOf(request.isShowRuntimePlan())); + } + if (!request.isAsync()) { + builder.addParameter(MODE, request.isAsync() ? MODE_ASYNC : MODE_SYNC); + } + + return builder.build(); + } + + /** + * Builds the query result {@link URI} given the {@link QueryResultRequest} + * + * @param resultRequest + * result request + * @param restIpAddress + * rest server's ip + * @param restPort + * port of the rest server + * @return generated {@link URI} + * @throws URISyntaxException + */ + public static URI buildQueryResultURI(QueryResultRequest resultRequest, String restIpAddress, int restPort) + throws URISyntaxException { + URIBuilder builder = new URIBuilder().setScheme("http").setHost(restIpAddress).setPort(restPort) + .setPath(QUERY_RESULT_ENDPOINT.replace("*", String.valueOf(resultRequest.getResultId()))); + + if (resultRequest.isShowMetrics()) { + builder.setParameter(METRICS, String.valueOf(resultRequest.isShowMetrics())); + } + + return builder.build(); + } + + /** + * Reads the entity from an {@link HttpEntity} + * + * @param entity + * entity instance to be read + * @return entity read by this method as a string + * @throws IOException + */ + public static String readEntity(HttpEntity entity) throws IOException { + StringBuilder responseBody = new StringBuilder(); + + try (InputStream in = entity.getContent()) { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String line; + while ((line = reader.readLine()) != null) { + responseBody.append(line); + } + } + return responseBody.toString(); + } + + /** + * Maps the object in the string representation to a java object. To map json + * entities, this method use {@link ObjectMapper}. For XML this method use + * {@link Unmarshaller}. + * + * @param entity + * string representation of the object + * @param type + * the class to which the string needs to be mapped to + * @param contentType + * json or XML + * @param <T> + * content's class type + * @return mapped object + * @throws IOException + * @throws JAXBException + */ + public static <T> T mapEntity(String entity, Class<T> type, String contentType) throws IOException, JAXBException { + if (contentType == null) { + contentType = CONTENT_TYPE_JSON; + } + + switch (contentType) { + case CONTENT_TYPE_XML: + JAXBContext jaxbContext = JAXBContext.newInstance(type); + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + return type.cast(unmarshaller.unmarshal(new StringReader(entity))); + case CONTENT_TYPE_JSON: + default: + ObjectMapper jsonMapper = new ObjectMapper(); + return jsonMapper.readValue(entity, type); + } + } +} http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/main/java/org/apache/vxquery/rest/Constants.java ---------------------------------------------------------------------- diff --git a/vxquery-rest/src/main/java/org/apache/vxquery/rest/Constants.java b/vxquery-rest/src/main/java/org/apache/vxquery/rest/Constants.java new file mode 100644 index 0000000..4ba79ec --- /dev/null +++ b/vxquery-rest/src/main/java/org/apache/vxquery/rest/Constants.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.vxquery.rest; + +public class Constants { + + private Constants() { + } + + public class Parameters { + public static final String STATEMENT = "statement"; + public static final String RESULT_ID = "resultId "; + public static final String COMPILE_ONLY = "compileOnly"; + public static final String OPTIMIZATION = "optimization"; + public static final String FRAME_SIZE = "frameSize"; + public static final String REPEAT_EXECUTIONS = "repeatExecutions"; + public static final String METRICS = "metrics"; + public static final String SHOW_AST = "showAbstractSyntaxTree"; + public static final String SHOW_TET = "showTranslatedExpressionTree"; + public static final String SHOW_OET = "showOptimizedExpressionTree"; + public static final String SHOW_RP = "showRuntimePlan"; + public static final String MODE = "mode"; + } + + public class URLs { + public static final String BASE_PATH = "/vxquery"; + + public static final String QUERY_ENDPOINT = BASE_PATH + "/query"; + public static final String QUERY_RESULT_ENDPOINT = BASE_PATH + "/query/result/*"; + } + + public class Properties { + public static final String AVAILABLE_PROCESSORS = "org.apache.vxquery.available_processors"; + public static final String LOCAL_NODE_CONTROLLERS = "org.apache.vxquery.local_nc"; + public static final String JOIN_HASH_SIZE = "org.apache.vxquery.join_hash"; + public static final String MAXIMUM_DATA_SIZE = "org.apache.vxquery.data_size"; + public static final String HDFS_CONFIG = "org.apache.vxquery.hdfs_config"; + } + + public class HttpHeaderValues { + public static final String CONTENT_TYPE_JSON = "application/json"; + public static final String CONTENT_TYPE_XML = "application/xml"; + } + + public class ErrorCodes { + public static final int PROBLEM_WITH_QUERY = 400; + public static final int UNFORSEEN_PROBLEM = 500; + public static final int INVALID_INPUT = 405; + public static final int NOT_FOUND = 404; + } + + public static final String RESULT_URL_PREFIX = "/vxquery/query/result/"; + + public static final String MODE_ASYNC = "async"; + public static final String MODE_SYNC = "sync"; +}
