You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fg...@apache.org on 2010/04/26 20:23:22 UTC

svn commit: r938173 - in /incubator/chemistry/opencmis/trunk/chemistry-opencmis-server: chemistry-opencmis-server-inmemory/ chemistry-opencmis-server-inmemory/src/main/antlr3/ chemistry-opencmis-server-inmemory/src/main/antlr3/org/ chemistry-opencmis-s...

Author: fguillaume
Date: Mon Apr 26 18:23:22 2010
New Revision: 938173

URL: http://svn.apache.org/viewvc?rev=938173&view=rev
Log:
CMIS-195: example use of CMISQLLexer: implement the beginning of a CMISQL query service for the inmemory implementation

Added:
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/opencmis/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/opencmis/inmemory/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/opencmis/inmemory/query/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryWalker.g   (with props)
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/DiscoveryServiceTest.java   (with props)
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/main/java/org/apache/chemistry/opencmis/server/support/query/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/main/java/org/apache/chemistry/opencmis/server/support/query/CalendarHelper.java   (with props)
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/query/
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/query/TestCalendarHelper.java   (with props)
Modified:
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/pom.xml
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/server/InMemoryDiscoveryServiceImpl.java
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/storedobj/impl/ObjectStoreImpl.java
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/AbstractServiceTst.java
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/ObjectServiceTest.java

Modified: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/pom.xml
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/pom.xml?rev=938173&r1=938172&r2=938173&view=diff
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/pom.xml (original)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/pom.xml Mon Apr 26 18:23:22 2010
@@ -29,6 +29,48 @@
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <!-- default phase: process-sources -->
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>chemistry-opencmis-server-support</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <includes>**/*.tokens</includes>
+                                </artifactItem>
+                            </artifactItems>
+                            <outputDirectory>target/generated-sources/antlr3</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr3-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <!-- default phase: process-sources -->
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>antlr</goal>
+                        </goals>
+                        <configuration>
+                            <libDirectory>target/generated-sources/antlr3/org/apache/chemistry/opencmis/server/support/query</libDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-war-plugin</artifactId>
                 <configuration>
                     <archive>
@@ -94,6 +136,11 @@
             <artifactId>chemistry-opencmis-server-support</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr-runtime</artifactId>
+            <version>3.1.3</version>
+        </dependency>
     </dependencies>
 
 </project>

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryWalker.g
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryWalker.g?rev=938173&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryWalker.g (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryWalker.g Mon Apr 26 18:23:22 2010
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
+ */
+/**
+ * CMISQL tree grammar, walker for the inmemory implementation.
+ * This aims at implementing proper semantics without any speed
+ * optimization.
+ */
+tree grammar InMemoryQueryWalker;
+
+options {
+    tokenVocab = CMISQLParser;
+    ASTLabelType = CommonTree;
+    output = AST;
+}
+
+@header {
+/*
+ * THIS FILE IS AUTO-GENERATED, DO NOT EDIT.
+ *
+ * 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.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
+ *
+ * THIS FILE IS AUTO-GENERATED, DO NOT EDIT.
+ */
+package org.apache.chemistry.opencmis.inmemory.query;
+
+import java.math.BigDecimal;
+
+import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoredObject;
+import org.apache.chemistry.opencmis.server.support.query.CalendarHelper;
+}
+
+@members {
+    public StoredObject object;
+
+    // public SimpleConnection connection;
+
+    public String errorMessage;
+
+    @Override
+    public void displayRecognitionError(String[] tokenNames,
+            RecognitionException e) {
+        if (errorMessage == null) {
+            String hdr = getErrorHeader(e);
+            String msg = getErrorMessage(e, tokenNames);
+            errorMessage = hdr + " " + msg;
+        }
+    }
+}
+
+query [StoredObject o] returns [String tableName, boolean matches]
+@init {
+    object = $o;
+    // connection = $ conn;
+}:
+    ^(SELECT DISTINCT? select_list from_clause where_clause order_by_clause?)
+    {
+        // TODO distinct
+        // TODO select_list
+        $tableName = $from_clause.tableName;
+        $matches = $where_clause.matches;
+        // TODO order_by_clause
+    }
+    ;
+
+select_list:
+      STAR
+    | ^(LIST select_sublist+)
+    ;
+
+select_sublist:
+      value_expression column_name?
+    | qualifier DOT STAR
+    ;
+
+value_expression returns [Object value]:
+      column_reference
+        {
+            $value = $column_reference.value;
+        }
+    | ^(FUNC SCORE)
+        {
+            $value = Double.valueOf(1);
+        }
+    // TODO provide extension points for other functions
+    ;
+
+column_reference returns [Object value]:
+    ^(COL qualifier? column_name)
+      {
+          String col = $column_name.start.getText();
+          // TODO should use query name
+          // $value = object.getIgnoreCase(col); // TODO error if unknown prop
+      }
+    ;
+
+// multi_valued_column_reference returns [Object value]:
+//    ^(COL qualifier? column_name)
+
+qualifier:
+      table_name
+//    | correlation_name
+    ;
+
+from_clause returns [String tableName]:
+    ^(FROM table_reference)
+      {
+          $tableName = $table_reference.tableName;
+      }
+    ;
+
+table_reference returns [String tableName]:
+    one_table table_join*
+      {
+          $tableName = $one_table.tableName;
+          // TODO joins
+      }
+    ;
+
+table_join:
+    ^(JOIN join_kind one_table join_specification?)
+    ;
+
+one_table returns [String tableName]:
+    ^(TABLE table_name correlation_name?)
+      {
+          $tableName = $table_name.text;
+      }
+    ;
+
+join_kind:
+    INNER | LEFT | OUTER;
+
+join_specification:
+    ^(ON column_reference EQ column_reference)
+    ;
+
+where_clause returns [boolean matches]:
+      ^(WHERE search_condition)
+        {
+            $matches = $search_condition.matches;
+        }
+    | /* nothing */
+        {
+            $matches = true;
+        }
+    ;
+
+search_condition returns [boolean matches]:
+    b1=boolean_term { $matches = $b1.matches; }
+    (OR b2=boolean_term { $matches |= $b2.matches; })*
+    ;
+
+boolean_term returns [boolean matches]:
+    b1=boolean_factor { $matches = $b1.matches; }
+    (AND b2=boolean_factor { $matches &= $b2.matches; })*
+    ;
+
+boolean_factor returns [boolean matches]:
+      b=boolean_test { $matches = $b.matches; }
+    | NOT b=boolean_test { $matches = ! $b.matches; }
+    ;
+
+boolean_test returns [boolean matches]:
+      predicate { $matches = $predicate.matches; }
+    | LPAR search_condition RPAR { $matches = $search_condition.matches; }
+    ;
+
+predicate returns [boolean matches]
+@init {
+    List<Object> literals;
+}:
+      ^(UN_OP IS_NULL arg) { $matches = $arg.value == null; }
+    | ^(UN_OP IS_NOT_NULL arg) { $matches = $arg.value != null; }
+    | ^(BIN_OP bin_op arg1=arg arg2=arg)
+        {
+            int token = $bin_op.start.getType();
+            Object value1 = $arg1.value;
+            Object value2 = $arg2.value;
+            switch (token) {
+                case EQ:
+                    $matches = value1 != null && value1.equals(value2);
+                    break;
+                case NEQ:
+                    $matches = value1 != null && value2 != null && ! value1.equals(value2);
+                    break;
+                case LT:
+                    throw new UnsupportedOperationException("<"); // TODO
+                case LTEQ:
+                    throw new UnsupportedOperationException("<="); // TODO
+                case GT:
+                    throw new UnsupportedOperationException(">"); // TODO
+                case GTEQ:
+                    throw new UnsupportedOperationException(">="); // TODO
+                case LIKE:
+                    throw new UnsupportedOperationException("LIKE "); // TODO
+                case NOT_LIKE:
+                    throw new UnsupportedOperationException("NOT LIKE"); // TODO
+                default:
+                    throw new UnwantedTokenException(token, input);
+            }
+        }
+    // | ^(BIN_OP_ANY bin_op_any arg mvc=multi_valued_column_reference)
+    | ^(FUNC bool_func_name { literals = new ArrayList<Object>(); }
+         (literal { literals.add($literal.value); })*)
+        {
+            int func = $bool_func_name.start.getType();
+            switch (func) {
+                case IN_FOLDER:
+                    throw new UnsupportedOperationException("IN_FOLDER"); // TODO
+                    // $matches = connection.isInFolder(object, literals.get(0));
+                    // break;
+                case IN_TREE:
+                    throw new UnsupportedOperationException("IN_TREE"); // TODO
+                    // $matches = connection.isInTree(object, literals.get(0));
+                    // break;
+                case CONTAINS:
+                    throw new UnsupportedOperationException("CONTAINS"); // TODO
+                    // $matches = connection.fulltextContains(object, literals);
+                    // break;
+                case ID:
+                    break;
+                default:
+                    throw new UnwantedTokenException(Token.INVALID_TOKEN_TYPE, input);
+            }
+        }
+    ;
+
+bin_op:
+    EQ | NEQ | LT | GT | LTEQ | GTEQ | LIKE | NOT_LIKE;
+
+bool_func_name:
+    IN_FOLDER | IN_TREE | CONTAINS | ID;
+
+arg returns [Object value]
+@init {
+    List<Object> literals;
+}:
+      v=value_expression { $value = $v.value; }
+    | l=literal { $value = $l.value; }
+    | ^(LIST { literals = new ArrayList<Object>(); }
+         (l=literal { literals.add($l.value); } )+)
+            { $value = literals; }
+    ;
+
+literal returns [Object value]:
+      NUM_LIT
+        {
+            try {
+                $value = Long.valueOf($NUM_LIT.text);
+            } catch (NumberFormatException e) {
+                $value = new BigDecimal($NUM_LIT.text);
+            }
+        }
+    | STRING_LIT
+        {
+            String s = $STRING_LIT.text;
+            $value = s.substring(1, s.length() - 1);
+        }
+    | TIME_LIT
+        {
+            String s = $TIME_LIT.text;
+            s = s.substring(s.indexOf('\'') + 1, s.length() - 1);
+            try {
+                $value = CalendarHelper.fromString(s);
+            } catch (IllegalArgumentException e) {
+                throw new UnwantedTokenException(Token.INVALID_TOKEN_TYPE, input);
+            }
+        }
+    | BOOL_LIT
+        {
+            $value = Boolean.valueOf($BOOL_LIT.text);
+        }
+    ;
+
+order_by_clause:
+    ^(ORDER_BY sort_specification+)
+    ;
+
+sort_specification:
+    column_reference ( ASC | DESC )
+    ;
+
+correlation_name:
+    ID;
+
+table_name:
+    ID;
+
+column_name:
+    ID;

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/antlr3/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryWalker.g
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/server/InMemoryDiscoveryServiceImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/server/InMemoryDiscoveryServiceImpl.java?rev=938173&r1=938172&r2=938173&view=diff
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/server/InMemoryDiscoveryServiceImpl.java (original)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/server/InMemoryDiscoveryServiceImpl.java Mon Apr 26 18:23:22 2010
@@ -18,30 +18,52 @@
  */
 package org.apache.chemistry.opencmis.inmemory.server;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.GregorianCalendar;
 import java.util.List;
 
+import org.antlr.runtime.ANTLRInputStream;
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.TokenSource;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.CommonTreeNodeStream;
 import org.apache.chemistry.opencmis.commons.api.ExtensionsData;
 import org.apache.chemistry.opencmis.commons.api.Holder;
 import org.apache.chemistry.opencmis.commons.api.ObjectData;
 import org.apache.chemistry.opencmis.commons.api.ObjectInFolderContainer;
 import org.apache.chemistry.opencmis.commons.api.ObjectList;
 import org.apache.chemistry.opencmis.commons.api.RepositoryInfo;
+import org.apache.chemistry.opencmis.commons.api.TypeDefinition;
 import org.apache.chemistry.opencmis.commons.api.server.CallContext;
 import org.apache.chemistry.opencmis.commons.enums.ChangeType;
 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ChangeEventInfoDataImpl;
 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl;
 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
+import org.apache.chemistry.opencmis.inmemory.query.InMemoryQueryWalker;
+import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStore;
 import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoreManager;
+import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoredObject;
+import org.apache.chemistry.opencmis.inmemory.storedobj.impl.ObjectStoreImpl;
+import org.apache.chemistry.opencmis.inmemory.types.PropertyCreationHelper;
 import org.apache.chemistry.opencmis.server.spi.CmisDiscoveryService;
 import org.apache.chemistry.opencmis.server.spi.ObjectInfoHolder;
+import org.apache.chemistry.opencmis.server.support.query.CMISQLLexer;
+import org.apache.chemistry.opencmis.server.support.query.CMISQLParser;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
-public class InMemoryDiscoveryServiceImpl implements CmisDiscoveryService {
+public class InMemoryDiscoveryServiceImpl extends InMemoryAbstractServiceImpl implements CmisDiscoveryService {
+
+    private static final Log LOG = LogFactory.getLog(InMemoryDiscoveryServiceImpl.class.getName());
 
-    private StoreManager fStoreManager;
     AtomLinkInfoProvider fAtomLinkProvider;
     InMemoryNavigationServiceImpl fNavigationService; // real implementation of
     // the service
@@ -49,7 +71,7 @@ public class InMemoryDiscoveryServiceImp
 
     public InMemoryDiscoveryServiceImpl(StoreManager storeManager, InMemoryRepositoryServiceImpl repSvc,
             InMemoryNavigationServiceImpl navSvc) {
-        fStoreManager = storeManager;
+        super(storeManager);
         fAtomLinkProvider = new AtomLinkInfoProvider(fStoreManager);
         fNavigationService = navSvc;
         fRepositoryService = repSvc;
@@ -100,25 +122,85 @@ public class InMemoryDiscoveryServiceImp
     public ObjectList query(CallContext context, String repositoryId, String statement, Boolean searchAllVersions,
             Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
             BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
-        // dummy implementation using hard coded values
 
-        // use descendants of root folder as result
-        RepositoryInfo rep = fRepositoryService.getRepositoryInfo(context, repositoryId, null);
-        String rootFolderId = rep.getRootFolderId();
-        ObjectListImpl objList = new ObjectListImpl();
-        List<ObjectInFolderContainer> tempRes = fNavigationService.getDescendants(context, repositoryId, rootFolderId,
-                BigInteger.valueOf(3), "*", includeAllowableActions, includeRelationships, renditionFilter, false,
-                extension, null);
+        LOG.debug("start query()");
+        checkRepositoryId(repositoryId);
+        ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
 
-        // convert ObjectInFolderContainerList to objectList
+        String user = context.getUsername();
+        String tableName = null;
         List<ObjectData> lod = new ArrayList<ObjectData>();
-        for (ObjectInFolderContainer obj : tempRes) {
-            convertList(lod, obj);
+        // iterate over all the objects and check for each if the query matches
+        for (String objectId : ((ObjectStoreImpl) objectStore).getIds()) {
+            StoredObject so = objectStore.getObjectById(objectId);
+            if (tableName != null) {
+                // type already available: check early
+                if (!typeMatches(context, repositoryId, tableName, so.getTypeId())) {
+                    continue;
+                }
+            }
+            InMemoryQueryWalker.query_return ret = queryStoredObject(statement, so);
+            if (tableName == null) {
+                // first time: check late
+                tableName = ret.tableName.toLowerCase();
+                if (!typeMatches(context, repositoryId, tableName, so.getTypeId())) {
+                    continue;
+                }
+            }
+            if (ret.matches) {
+                String filter = "*"; // TODO select_list
+                ObjectData od = PropertyCreationHelper.getObjectData(fStoreManager, so, filter, user,
+                        includeAllowableActions, includeRelationships, renditionFilter, false, false, null);
+                lod.add(od);
+            }
         }
+
+        // TODO order_by_clause
+
+        ObjectListImpl objList = new ObjectListImpl();
         objList.setObjects(lod);
         objList.setNumItems(BigInteger.valueOf(lod.size()));
 
+        LOG.debug("stop query()");
         return objList;
     }
 
+    protected boolean typeMatches(CallContext context, String repositoryId, String tableName, String typeId) {
+        do {
+            TypeDefinition td = fRepositoryService.getTypeDefinition(context, repositoryId, typeId, null);
+            if (tableName.equals(td.getQueryName().toLowerCase())) {
+                return true;
+            }
+            // check parent type
+            typeId = td.getParentTypeId();
+        } while (typeId != null);
+        return false;
+    }
+
+    protected InMemoryQueryWalker.query_return queryStoredObject(String statement, StoredObject so) {
+        try {
+            CharStream input = new ANTLRInputStream(new ByteArrayInputStream(statement.getBytes("UTF-8")));
+            TokenSource lexer = new CMISQLLexer(input);
+            TokenStream tokens = new CommonTokenStream(lexer);
+            CMISQLParser parser = new CMISQLParser(tokens);
+            CMISQLParser.query_return query = parser.query();
+            if (parser.errorMessage != null) {
+                throw new CmisRuntimeException("Cannot parse query: " + statement + " (" + parser.errorMessage + ")");
+            }
+            CommonTree tree = (CommonTree) query.getTree();
+            CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
+            nodes.setTokenStream(tokens);
+            InMemoryQueryWalker walker = new InMemoryQueryWalker(nodes);
+            InMemoryQueryWalker.query_return res = walker.query(so);
+            if (walker.errorMessage != null) {
+                throw new CmisRuntimeException("Cannot parse query: " + statement + " (" + walker.errorMessage + ")");
+            }
+            return res;
+        } catch (IOException e) {
+            throw new CmisRuntimeException(e.getMessage(), e);
+        } catch (RecognitionException e) {
+            throw new CmisRuntimeException("Cannot parse query: " + statement, e);
+        }
+    }
+
 }

Modified: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/storedobj/impl/ObjectStoreImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/storedobj/impl/ObjectStoreImpl.java?rev=938173&r1=938172&r2=938173&view=diff
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/storedobj/impl/ObjectStoreImpl.java (original)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/storedobj/impl/ObjectStoreImpl.java Mon Apr 26 18:23:22 2010
@@ -20,17 +20,14 @@ package org.apache.chemistry.opencmis.in
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.Map.Entry;
 
 import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
 import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Document;
 import org.apache.chemistry.opencmis.inmemory.storedobj.api.DocumentVersion;
-import org.apache.chemistry.opencmis.inmemory.storedobj.api.Filing;
 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Folder;
 import org.apache.chemistry.opencmis.inmemory.storedobj.api.MultiFiling;
 import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStore;
@@ -40,9 +37,9 @@ import org.apache.chemistry.opencmis.inm
 
 /**
  * InMemory folder implementation
- * 
+ *
  * @author Jens
- * 
+ *
  */
 
 public class ObjectStoreImpl implements ObjectStore {
@@ -70,7 +67,7 @@ public class ObjectStoreImpl implements 
 
     /*
      * (non-Javadoc)
-     * 
+     *
      * @see
      * org.opencmis.client.provider.spi.inmemory.storedobj.impl.ObjectStore#
      * getRootFolder()
@@ -81,7 +78,7 @@ public class ObjectStoreImpl implements 
 
     /*
      * (non-Javadoc)
-     * 
+     *
      * @see
      * org.opencmis.client.provider.spi.inmemory.storedobj.impl.ObjectStore#
      * getFolderByPath(java.lang .String)
@@ -111,7 +108,7 @@ public class ObjectStoreImpl implements 
 
     /*
      * (non-Javadoc)
-     * 
+     *
      * @see
      * org.opencmis.client.provider.spi.inmemory.storedobj.impl.ObjectStore#
      * getObjectById(java.lang .String)
@@ -124,7 +121,7 @@ public class ObjectStoreImpl implements 
 
     /*
      * (non-Javadoc)
-     * 
+     *
      * @see
      * org.opencmis.client.provider.spi.inmemory.storedobj.impl.ObjectStore#
      * deleteObject(java.lang .String)
@@ -187,7 +184,7 @@ public class ObjectStoreImpl implements 
         fStoredObjectMap.remove(id);
     }
 
-    Set<String> getIds() {
+    public Set<String> getIds() {
         Set<String> entries = fStoredObjectMap.keySet();
         return entries;
     }

Modified: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/AbstractServiceTst.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/AbstractServiceTst.java?rev=938173&r1=938172&r2=938173&view=diff
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/AbstractServiceTst.java (original)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/AbstractServiceTst.java Mon Apr 26 18:23:22 2010
@@ -21,6 +21,7 @@ import org.apache.chemistry.opencmis.com
 import org.apache.chemistry.opencmis.commons.api.BindingsObjectFactory;
 import org.apache.chemistry.opencmis.commons.api.CmisBinding;
 import org.apache.chemistry.opencmis.commons.api.ContentStream;
+import org.apache.chemistry.opencmis.commons.api.DiscoveryService;
 import org.apache.chemistry.opencmis.commons.api.ExtensionsData;
 import org.apache.chemistry.opencmis.commons.api.MultiFilingService;
 import org.apache.chemistry.opencmis.commons.api.NavigationService;
@@ -54,6 +55,7 @@ public class AbstractServiceTst /* exten
     protected RepositoryService fRepSvc;
     protected VersioningService fVerSvc;
     protected MultiFilingService fMultiSvc;
+    protected DiscoveryService fDiscSvc;
     protected DummyCallContext fTestCallContext;
     private String fTypeCreatorClassName;
     protected boolean fUseClientProviderInterface;
@@ -327,7 +329,7 @@ public class AbstractServiceTst /* exten
 
     /**
      * Instantiates the services by using directly the service implementations.
-     * 
+     *
      * @param parameters
      *            configuration parameters for client provider interface and
      *            in-memory provider
@@ -341,11 +343,12 @@ public class AbstractServiceTst /* exten
         fNavSvc = inMemSpi.getNavigationService();
         fVerSvc = inMemSpi.getVersioningService();
         fMultiSvc = inMemSpi.getMultiFilingService();
+        fDiscSvc = inMemSpi.getDiscoveryService();
     }
 
     /**
      * Instantiates the services by using the client provider interface.
-     * 
+     *
      * @param parameters
      *            configuration parameters for client provider interface and
      *            in-memory provider
@@ -370,6 +373,7 @@ public class AbstractServiceTst /* exten
         fNavSvc = binding.getNavigationService();
         fVerSvc = binding.getVersioningService();
         fMultiSvc = binding.getMultiFilingService();
+        fDiscSvc = binding.getDiscoveryService();
     }
 
     protected String getStringProperty(ObjectData objData, String propertyKey) {

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/DiscoveryServiceTest.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/DiscoveryServiceTest.java?rev=938173&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/DiscoveryServiceTest.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/DiscoveryServiceTest.java Mon Apr 26 18:23:22 2010
@@ -0,0 +1,98 @@
+/*
+ * 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.chemistry.opencmis.inmemory;
+
+import static org.junit.Assert.assertEquals;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.chemistry.opencmis.commons.api.ObjectList;
+import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
+import org.apache.chemistry.opencmis.inmemory.ObjectServiceTest.ObjectTestTypeSystemCreator;
+import org.apache.chemistry.opencmis.util.repository.ObjectGenerator;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DiscoveryServiceTest extends AbstractServiceTst {
+
+    private static Log log = LogFactory.getLog(DiscoveryServiceTest.class);
+    private static final String TEST_FOLDER_TYPE_ID = ObjectServiceTest.TEST_FOLDER_TYPE_ID;
+    private static final String TEST_DOCUMENT_TYPE_ID = ObjectServiceTest.TEST_DOCUMENT_TYPE_ID;
+    private static final String TEST_FOLDER_STRING_PROP_ID = ObjectServiceTest.TEST_FOLDER_STRING_PROP_ID;
+    private static final String TEST_DOCUMENT_STRING_PROP_ID = ObjectServiceTest.TEST_DOCUMENT_STRING_PROP_ID;
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        super.setTypeCreatorClass(ObjectTestTypeSystemCreator.class.getName());
+        super.setUp();
+    }
+
+    @Test
+    public void testQuery() throws Exception {
+        log.info("starting testQuery() ...");
+
+        ObjectGenerator gen = new ObjectGenerator(fFactory, fNavSvc, fObjSvc, fRepositoryId);
+        gen.setNumberOfDocumentsToCreatePerFolder(3);
+        gen.setDocumentTypeId(TEST_DOCUMENT_TYPE_ID);
+        gen.setFolderTypeId(TEST_FOLDER_TYPE_ID);
+
+        List<String> propsToSet = new ArrayList<String>();
+        propsToSet.add(TEST_DOCUMENT_STRING_PROP_ID);
+        gen.setDocumentPropertiesToGenerate(propsToSet);
+
+        propsToSet = new ArrayList<String>();
+        propsToSet.add(TEST_FOLDER_STRING_PROP_ID);
+        gen.setFolderPropertiesToGenerate(propsToSet);
+
+        gen.createFolderHierachy(2, 2, fRootFolderId);
+
+        Boolean searchAllVersions = Boolean.FALSE;
+        Boolean includeAllowableActions = Boolean.FALSE;
+        IncludeRelationships includeRelationships = IncludeRelationships.NONE;
+        String renditionFilter = null;
+        BigInteger maxItems = null;
+        BigInteger skipCount = null;
+
+        String statement = "SELECT * FROM cmis:document";
+        ObjectList res = fDiscSvc.query(fRepositoryId, statement, searchAllVersions, includeAllowableActions,
+                includeRelationships, renditionFilter, maxItems, skipCount, null);
+        // 3 at level 1 + 3*2 at level 2 = 9
+        assertEquals(BigInteger.valueOf(9), res.getNumItems());
+
+        statement = "SELECT * FROM cmis:folder";
+        res = fDiscSvc.query(fRepositoryId, statement, searchAllVersions, includeAllowableActions,
+                includeRelationships, renditionFilter, maxItems, skipCount, null);
+        // root + 2 at level 1 + 2*2 at level 2 = 7
+        assertEquals(BigInteger.valueOf(7), res.getNumItems());
+
+        statement = "SELECT * FROM cmis:folder";
+        res = fDiscSvc.query(fRepositoryId, statement, searchAllVersions, includeAllowableActions,
+                includeRelationships, renditionFilter, maxItems, skipCount, null);
+        // root + 2 at level 1 + 2*2 at level 2 = 7
+        assertEquals(BigInteger.valueOf(7), res.getNumItems());
+
+        log.info("... testQuery() finished.");
+    }
+
+}

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/DiscoveryServiceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/DiscoveryServiceTest.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/ObjectServiceTest.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/ObjectServiceTest.java?rev=938173&r1=938172&r2=938173&view=diff
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/ObjectServiceTest.java (original)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/ObjectServiceTest.java Mon Apr 26 18:23:22 2010
@@ -70,10 +70,10 @@ import static org.junit.Assert.*;
 public class ObjectServiceTest extends AbstractServiceTst {
 
     private static Log log = LogFactory.getLog(ObjectServiceTest.class);
-    private static final String TEST_FOLDER_TYPE_ID = "MyFolderType";
-    private static final String TEST_DOCUMENT_TYPE_ID = "MyDocumentType";
-    private static final String TEST_FOLDER_STRING_PROP_ID = "MyFolderStringProp";
-    private static final String TEST_DOCUMENT_STRING_PROP_ID = "MyDocumentStringProp";
+    public static final String TEST_FOLDER_TYPE_ID = "MyFolderType";
+    public static final String TEST_DOCUMENT_TYPE_ID = "MyDocumentType";
+    public static final String TEST_FOLDER_STRING_PROP_ID = "MyFolderStringProp";
+    public static final String TEST_DOCUMENT_STRING_PROP_ID = "MyDocumentStringProp";
     private static final String TEST_CUSTOM_DOCUMENT_TYPE_ID = "MyCustomDocumentType";
     private static final String TEST_INHERITED_CUSTOM_DOCUMENT_TYPE_ID = "MyCustomInheritedDocType";
     private static final String TEST_DOCUMENT_MY_STRING_PROP_ID = "MyCustomDocumentStringProp";
@@ -890,7 +890,7 @@ public class ObjectServiceTest extends A
 
         /**
          * create root types and a sample type for folder and document
-         * 
+         *
          * @return typesMap map filled with created types
          */
         public List<TypeDefinition> createTypesList() {

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/main/java/org/apache/chemistry/opencmis/server/support/query/CalendarHelper.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/main/java/org/apache/chemistry/opencmis/server/support/query/CalendarHelper.java?rev=938173&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/main/java/org/apache/chemistry/opencmis/server/support/query/CalendarHelper.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/main/java/org/apache/chemistry/opencmis/server/support/query/CalendarHelper.java Mon Apr 26 18:23:22 2010
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
+ */
+package org.apache.chemistry.opencmis.server.support.query;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Helper dealing with conversion of {@link Calendar} to and from the string
+ * format specified by CMISQL.
+ */
+public class CalendarHelper {
+
+    private static final Pattern CMISQL_PATTERN = Pattern.compile( //
+            "(\\d{4})-(\\d{2})-(\\d{2})[Tt]" + "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?"
+                    + "(?:[Zz]|([+-]\\d{2}:\\d{2}))");
+
+    private CalendarHelper() {
+        // utility class
+    }
+
+    /**
+     * Converts a CMISQL date string representation to a
+     * {@link GregorianCalendar}.
+     * <p>
+     * Parses {@code YYYY-HH-MMThh:mm:ss.sss+hh:mm}, or a {@code Z} for the
+     * timezone, and with {@code .sss} being optional.
+     *
+     * @param datetime
+     *            the string representation in CMISQL format
+     * @return the created instance
+     */
+    public static GregorianCalendar fromString(String datetime) {
+        Matcher m = CMISQL_PATTERN.matcher(datetime);
+        if (!m.matches()) {
+            throw new IllegalArgumentException("Invalid datetime format: " + datetime);
+        }
+        String tz = m.group(8);
+        GregorianCalendar cal = (GregorianCalendar) GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"
+                + (tz == null ? "" : tz)));
+        cal.set(Calendar.YEAR, Integer.parseInt(m.group(1)));
+        cal.set(Calendar.MONTH, Integer.parseInt(m.group(2)) - 1);
+        cal.set(Calendar.DATE, Integer.parseInt(m.group(3)));
+        cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(4)));
+        cal.set(Calendar.MINUTE, Integer.parseInt(m.group(5)));
+        cal.set(Calendar.SECOND, Integer.parseInt(m.group(6)));
+        String decimals = m.group(7);
+        int ms = decimals == null ? 0 : Integer.parseInt((decimals + "00").substring(0, 3));
+        cal.set(Calendar.MILLISECOND, ms);
+        return cal;
+    }
+
+    /**
+     * Converts a Calendar to its CMISQL string representation.
+     *
+     * @param cal
+     *            a {@link Calendar}
+     * @return the CMISQL string representation
+     */
+    public static String toString(Calendar cal) {
+        StringBuilder buf = new StringBuilder(28);
+        toString(cal, buf);
+        return buf.toString();
+    }
+
+    /**
+     * Converts a Calendar to its CMISQL string representation.
+     *
+     * @param cal
+     *            a {@link Calendar}
+     * @param buf
+     *            a buffer in which to add the CMISQL string representation
+     */
+    public static void toString(Calendar cal, StringBuilder buf) {
+        buf.append(cal.get(Calendar.YEAR));
+        buf.append('-');
+        int f = cal.get(Calendar.MONTH);
+        if (f < 9) {
+            buf.append('0');
+        }
+        buf.append(f + 1);
+        buf.append('-');
+        f = cal.get(Calendar.DATE);
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        buf.append('T');
+        f = cal.get(Calendar.HOUR_OF_DAY);
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        buf.append(':');
+        f = cal.get(Calendar.MINUTE);
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        buf.append(':');
+        f = cal.get(Calendar.SECOND);
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        buf.append('.');
+        f = cal.get(Calendar.MILLISECOND);
+        if (f < 100) {
+            buf.append('0');
+        }
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        int offset = cal.getTimeZone().getOffset(cal.getTimeInMillis()) / 60000;
+        if (offset == 0) {
+            buf.append('Z');
+        } else {
+            char sign;
+            if (offset < 0) {
+                offset = -offset;
+                sign = '-';
+            } else {
+                sign = '+';
+            }
+            buf.append(sign);
+            f = offset / 60;
+            if (f < 10) {
+                buf.append('0');
+            }
+            buf.append(f);
+            buf.append(':');
+            f = offset % 60;
+            if (f < 10) {
+                buf.append('0');
+            }
+            buf.append(f);
+        }
+    }
+
+}

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/main/java/org/apache/chemistry/opencmis/server/support/query/CalendarHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/main/java/org/apache/chemistry/opencmis/server/support/query/CalendarHelper.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/query/TestCalendarHelper.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/query/TestCalendarHelper.java?rev=938173&view=auto
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/query/TestCalendarHelper.java (added)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/query/TestCalendarHelper.java Mon Apr 26 18:23:22 2010
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
+ */
+package org.apache.chemistry.opencmis.server.support.query;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.junit.Test;
+
+public class TestCalendarHelper {
+
+    @Test
+    public void testToString1() {
+        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT+07:30"));
+        cal.set(Calendar.YEAR, 2009);
+        cal.set(Calendar.MONTH, 0);
+        cal.set(Calendar.DATE, 2);
+        cal.set(Calendar.HOUR_OF_DAY, 3);
+        cal.set(Calendar.MINUTE, 4);
+        cal.set(Calendar.SECOND, 5);
+        cal.set(Calendar.MILLISECOND, 6);
+        assertEquals("2009-01-02T03:04:05.006+07:30", CalendarHelper.toString(cal));
+    }
+
+    @Test
+    public void testToString2() {
+        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT-06:00"));
+        cal.set(Calendar.YEAR, 2008);
+        cal.set(Calendar.MONTH, 11);
+        cal.set(Calendar.DATE, 31);
+        cal.set(Calendar.HOUR_OF_DAY, 23);
+        cal.set(Calendar.MINUTE, 59);
+        cal.set(Calendar.SECOND, 59);
+        cal.set(Calendar.MILLISECOND, 999);
+        assertEquals("2008-12-31T23:59:59.999-06:00", CalendarHelper.toString(cal));
+    }
+
+    @Test
+    public void testToString3() {
+        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"));
+        cal.set(Calendar.YEAR, 2008);
+        cal.set(Calendar.MONTH, 0);
+        cal.set(Calendar.DATE, 1);
+        cal.set(Calendar.HOUR_OF_DAY, 1);
+        cal.set(Calendar.MINUTE, 1);
+        cal.set(Calendar.SECOND, 1);
+        cal.set(Calendar.MILLISECOND, 1);
+        assertEquals("2008-01-01T01:01:01.001Z", CalendarHelper.toString(cal));
+    }
+
+    @Test
+    public void testFromString() {
+        Calendar cal;
+        cal = CalendarHelper.fromString("2009-07-14T12:00:00.123-06:30");
+        assertEquals("2009-07-14T12:00:00.123-06:30", CalendarHelper.toString(cal));
+        cal = CalendarHelper.fromString("2009-07-14T12:00:00Z");
+        assertEquals("2009-07-14T12:00:00.000Z", CalendarHelper.toString(cal));
+        cal = CalendarHelper.fromString("2009-07-14T12:00:00.5Z");
+        assertEquals("2009-07-14T12:00:00.500Z", CalendarHelper.toString(cal));
+        cal = CalendarHelper.fromString("2009-07-14T12:00:00.44Z");
+        assertEquals("2009-07-14T12:00:00.440Z", CalendarHelper.toString(cal));
+        cal = CalendarHelper.fromString("2009-07-14T12:00:00.333Z");
+        assertEquals("2009-07-14T12:00:00.333Z", CalendarHelper.toString(cal));
+    }
+
+}

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/query/TestCalendarHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/query/TestCalendarHelper.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-support/src/test/java/org/apache/chemistry/opencmis/server/support/query/TestCalendarHelper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain