From: Sanjay Dalal Date: Tue, 26 Jan 2010 17:27:05 +0000 (+0000) Subject: cspace-789 partial search on account. query parameters are sn for screenname, uid... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=104bf62e8b098579d42f8619fdb0148e3dd700fd;p=tmp%2Fjakarta-migration.git cspace-789 partial search on account. query parameters are sn for screenname, uid for userid, email for email. query parameters could be ANDed. AccountJpaFilter has where clause test: added search tests on account M services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClient.java M services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java M services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java M services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java A services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountJpaFilter.java A services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageConstants.java M services/account/client/src/test/java/org/collectionspace/services/account/client/test/AccountServiceTest.java M services/account/client/src/main/java/org/collectionspace/services/client/AccountClient.java M services/account/client/src/main/java/org/collectionspace/services/client/AccountProxy.java _M services/organization/client --- diff --git a/services/account/client/src/main/java/org/collectionspace/services/client/AccountClient.java b/services/account/client/src/main/java/org/collectionspace/services/client/AccountClient.java index 286108e79..05175be33 100644 --- a/services/account/client/src/main/java/org/collectionspace/services/client/AccountClient.java +++ b/services/account/client/src/main/java/org/collectionspace/services/client/AccountClient.java @@ -88,8 +88,8 @@ public class AccountClient extends BaseServiceClient { } - public ClientResponse readSearchList(String screenName) { - return accountProxy.readSearchList(screenName); + public ClientResponse readSearchList(String screenName, String uid, String email) { + return accountProxy.readSearchList(screenName, uid, email); } diff --git a/services/account/client/src/main/java/org/collectionspace/services/client/AccountProxy.java b/services/account/client/src/main/java/org/collectionspace/services/client/AccountProxy.java index 940d701a8..ce724ff2c 100644 --- a/services/account/client/src/main/java/org/collectionspace/services/client/AccountProxy.java +++ b/services/account/client/src/main/java/org/collectionspace/services/client/AccountProxy.java @@ -58,7 +58,7 @@ public interface AccountProxy { @GET @Produces({"application/xml"}) - ClientResponse readSearchList(@QueryParam("sn") String screenName); + ClientResponse readSearchList(@QueryParam("sn") String screenName, @QueryParam("uid") String uid, @QueryParam("email") String email); //(C)reate @POST diff --git a/services/account/client/src/test/java/org/collectionspace/services/account/client/test/AccountServiceTest.java b/services/account/client/src/test/java/org/collectionspace/services/account/client/test/AccountServiceTest.java index 810a99b60..09bb984ad 100644 --- a/services/account/client/src/test/java/org/collectionspace/services/account/client/test/AccountServiceTest.java +++ b/services/account/client/src/test/java/org/collectionspace/services/account/client/test/AccountServiceTest.java @@ -58,10 +58,11 @@ public class AccountServiceTest extends AbstractServiceTest { private String knownResourceId = null; private String resource1Id = null; private String resource2Id = null; - + private String resource3Id = null; /* * This method is called only by the parent class, AbstractServiceTest */ + @Override protected String getServicePathComponent() { return client.getServicePathComponent(); @@ -173,6 +174,15 @@ public class AccountServiceTest extends AbstractServiceTest { invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); resource2Id = extractId(res); + + AccountsCommon account3 = + createAccountInstance("dj", "hithere10", "dj@dinoland.com", true, true, true); + res = client.create(account3); + statusCode = res.getStatus(); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + resource3Id = extractId(res); } // Failure outcomes @@ -277,13 +287,69 @@ public class AccountServiceTest extends AbstractServiceTest { @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, dependsOnMethods = {"createList", "read"}) - public void readSearchList(String testName) throws Exception { + public void searchScreenName(String testName) throws Exception { + + // Perform setup. + setupReadList(testName); + + // Submit the request to the service and store the response. + ClientResponse res = client.readSearchList("tom", null, null); + AccountsCommonList list = res.getEntity(); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + if (logger.isDebugEnabled()) { + logger.debug(testName + ": status = " + statusCode); + } + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + Assert.assertEquals(1, list.getAccountListItem().size()); + // Optionally output additional data about list members for debugging. + boolean iterateThroughList = true; + if (iterateThroughList && logger.isDebugEnabled()) { + printList(testName, list); + } + } + + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"createList", "read"}) + public void searchUserId(String testName) throws Exception { + + // Perform setup. + setupReadList(testName); + + // Submit the request to the service and store the response. + ClientResponse res = client.readSearchList(null, "tom", null); + AccountsCommonList list = res.getEntity(); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + if (logger.isDebugEnabled()) { + logger.debug(testName + ": status = " + statusCode); + } + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + Assert.assertEquals(1, list.getAccountListItem().size()); + // Optionally output additional data about list members for debugging. + boolean iterateThroughList = true; + if (iterateThroughList && logger.isDebugEnabled()) { + printList(testName, list); + } + } + + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"createList", "read"}) + public void searchEmail(String testName) throws Exception { // Perform setup. setupReadList(testName); // Submit the request to the service and store the response. - ClientResponse res = client.readSearchList("tom"); + ClientResponse res = client.readSearchList(null, null, "dinoland"); AccountsCommonList list = res.getEntity(); int statusCode = res.getStatus(); @@ -295,7 +361,35 @@ public class AccountServiceTest extends AbstractServiceTest { Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + Assert.assertEquals(2, list.getAccountListItem().size()); + // Optionally output additional data about list members for debugging. + boolean iterateThroughList = true; + if (iterateThroughList && logger.isDebugEnabled()) { + printList(testName, list); + } + } + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"createList", "read"}) + public void searchScreenNameEmail(String testName) throws Exception { + + // Perform setup. + setupReadList(testName); + + // Submit the request to the service and store the response. + ClientResponse res = client.readSearchList("tom", null, "jerry"); + AccountsCommonList list = res.getEntity(); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + if (logger.isDebugEnabled()) { + logger.debug(testName + ": status = " + statusCode); + } + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + Assert.assertEquals(1, list.getAccountListItem().size()); // Optionally output additional data about list members for debugging. boolean iterateThroughList = true; if (iterateThroughList && logger.isDebugEnabled()) { @@ -632,6 +726,12 @@ public class AccountServiceTest extends AbstractServiceTest { Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + res = client.delete(resource3Id); + statusCode = res.getStatus(); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } // Failure outcomes diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java index 6863aca45..ec11b7dd9 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java @@ -33,7 +33,6 @@ import org.collectionspace.services.common.document.AbstractDocumentHandler; import org.collectionspace.services.common.document.BadRequestException; import org.collectionspace.services.common.document.DocumentFilter; import org.collectionspace.services.common.document.DocumentWrapper; -import org.collectionspace.services.common.storage.jpa.JpaDocumentFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -161,26 +160,15 @@ public class AccountDocumentHandler @Override public DocumentFilter createDocumentFilter() { - return new JpaDocumentFilter(); + return new AccountJpaFilter(); } - private void setWhereForGetAll(StringBuilder strBld) { - DocumentFilter filter = getDocumentFilter(); - String screenName = null; - if (screenName != null && !screenName.isEmpty()) { - String ptClause = - "WHERE UPPER(a.screenName)" - + " LIKE " - + ":sn"; - filter.addQueryParam("sn", "%" + screenName.toUpperCase() + "%"); - filter.setWhereClause(ptClause); - } - } /** * sanitize removes data not needed to be sent to the consumer * @param account */ private void sanitize(AccountsCommon account) { account.setPassword(null); + } } diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountJpaFilter.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountJpaFilter.java new file mode 100644 index 000000000..17635853c --- /dev/null +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountJpaFilter.java @@ -0,0 +1,137 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * 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. + *//** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * 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. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.collectionspace.services.account.storage; + +import java.util.ArrayList; +import java.util.List; +import org.collectionspace.services.common.storage.jpa.JpaDocumentFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author + */ +public class AccountJpaFilter extends JpaDocumentFilter { + + private final Logger logger = LoggerFactory.getLogger(AccountJpaFilter.class); + + @Override + public List buildWhereForSearch(StringBuilder queryStrBldr) { + + List paramList = new ArrayList(); + boolean hasWhere = false; + //TODO: add tenant id + + String screenName = null; + List snvals = getQueryParam(AccountStorageConstants.Q_SCREEN_NAME); + if (snvals != null) { + screenName = snvals.get(0); + } + if (null != screenName && !screenName.isEmpty()) { + hasWhere = true; + queryStrBldr.append(" WHERE"); + queryStrBldr.append(" UPPER(a." + AccountStorageConstants.SCREEN_NAME + ")"); + queryStrBldr.append(" LIKE"); + queryStrBldr.append(" :" + AccountStorageConstants.Q_SCREEN_NAME); + paramList.add(new ParamBinding(AccountStorageConstants.Q_SCREEN_NAME, "%" + + screenName.toUpperCase() + "%")); + } + + String uid = null; + List uidvals = getQueryParam(AccountStorageConstants.Q_USER_ID); + if (uidvals != null) { + uid = uidvals.get(0); + } + if (null != uid && !uid.isEmpty()) { + if (hasWhere) { + queryStrBldr.append(" AND"); + } else { + queryStrBldr.append(" WHERE"); + } + queryStrBldr.append(" UPPER(a." + AccountStorageConstants.USER_ID + ")"); + queryStrBldr.append(" LIKE"); + queryStrBldr.append(" :" + AccountStorageConstants.Q_USER_ID); + paramList.add(new ParamBinding(AccountStorageConstants.Q_USER_ID, "%" + + uid.toUpperCase() + "%")); + hasWhere = true; + } + + String email = null; + List emailvals = getQueryParam(AccountStorageConstants.Q_EMAIL); + if (emailvals != null) { + email = emailvals.get(0); + } + if (null != email && !email.isEmpty()) { + if (hasWhere) { + queryStrBldr.append(" AND"); + } else { + queryStrBldr.append(" WHERE"); + } + queryStrBldr.append(" UPPER(a." + AccountStorageConstants.EMAIL + ")"); + queryStrBldr.append(" LIKE"); + queryStrBldr.append(" :" + AccountStorageConstants.Q_EMAIL); + paramList.add(new ParamBinding(AccountStorageConstants.Q_EMAIL, "%" + + email.toUpperCase() + "%")); + hasWhere = true; + } + + if (logger.isDebugEnabled()) { + logger.debug("query=" + queryStrBldr.toString()); + } + + return paramList; + } + + @Override + public List buildWhere(StringBuilder queryStrBldr) { + return new ArrayList(); + } +} diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java index 0e1dcd8f0..f0d479ca5 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java @@ -23,8 +23,6 @@ */ package org.collectionspace.services.account.storage; -import java.util.ArrayList; -import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Query; diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageConstants.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageConstants.java new file mode 100644 index 000000000..35b8e250a --- /dev/null +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageConstants.java @@ -0,0 +1,67 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * 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. + *//** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * 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. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.collectionspace.services.account.storage; + +/** + * AccountStorageConstants declares query params, etc. + * @author + */ +public class AccountStorageConstants { + + final public static String Q_SCREEN_NAME = "sn"; + final public static String Q_USER_ID= "uid"; + final public static String Q_EMAIL = "email"; + + + final public static String SCREEN_NAME = "screenName"; + final public static String USER_ID = "userId"; + final public static String EMAIL = "email"; +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java b/services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java index 971b8a423..72fb4d30a 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java +++ b/services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java @@ -17,12 +17,14 @@ */ package org.collectionspace.services.common.document; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; -import java.util.Map; import javax.ws.rs.core.MultivaluedMap; import org.collectionspace.services.common.query.IQueryManager; +//TODO: would be great to not rely on resteasy directly +import org.jboss.resteasy.specimpl.MultivaluedMapImpl; + /** * DocumentFilter bundles simple query filtering parameters. * It is designed to be used with filtered get and search calls to RepositoryClient. @@ -38,8 +40,51 @@ public class DocumentFilter { protected String whereClause; // Filtering clause. Omit the "WHERE". protected int startPage; // Pagination offset for list results protected int pageSize; // Pagination limit for list results - private MultivaluedMap queryParams; + private MultivaluedMap queryParams = new MultivaluedMapImpl(); + + + /** + * ParamBinding encapsulates parameter binding for query + */ + public static class ParamBinding { + + private String name; + private Object value; + + public ParamBinding(String name, Object value) { + this.name = name; + this.value = value; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + /** + * @return the value + */ + public Object getValue() { + return value; + } + + /** + * @param value the value to set + */ + public void setValue(Object value) { + this.value = value; + } + } + public DocumentFilter() { this("", 0, defaultPageSize); // Use empty string for easy concatenation } @@ -114,6 +159,24 @@ public class DocumentFilter { } } + /** + * buildWhereClause builds where clause for search query + * @param queryStrBldr query string to append with where clause + * @return parameter binding + */ + public List buildWhereForSearch(StringBuilder queryStrBldr) { + return new ArrayList(); + } + + /** + * buildWhereClause builds where clause for get, update or delete + * @param queryStrBldr query string to append with where clause + * @return parameter binding + */ + public List buildWhere(StringBuilder queryStrBldr) { + return new ArrayList(); + } + /** * @return the specified (0-based) page offset */ diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClient.java b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClient.java index 4438049ee..9e71d811c 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClient.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClient.java @@ -121,18 +121,19 @@ public class JpaStorageClient implements StorageClient { EntityManager em = null; try { handler.prepare(Action.GET); - StringBuilder queryStr = new StringBuilder("SELECT a FROM "); - queryStr.append(getEntityName(ctx)); - queryStr.append(" a"); - queryStr.append(" WHERE csid = :csid"); + StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM "); + queryStrBldr.append(getEntityName(ctx)); + queryStrBldr.append(" a"); + queryStrBldr.append(" WHERE csid = :csid"); //TODO: add tenant id String where = docFilter.getWhereClause(); if ((null != where) && (where.length() > 0)) { - queryStr.append(" AND " + where); + queryStrBldr.append(" AND " + where); } emf = getEntityManagerFactory(); em = emf.createEntityManager(); - Query q = em.createQuery(queryStr.toString()); + String queryStr = queryStrBldr.toString(); //for debugging + Query q = em.createQuery(queryStr); q.setParameter("csid", id); //TODO: add tenant id @@ -201,18 +202,18 @@ public class JpaStorageClient implements StorageClient { try { handler.prepare(Action.GET_ALL); - StringBuilder strBld = new StringBuilder("SELECT a FROM "); - strBld.append(getEntityName(ctx)); - strBld.append(" a"); + StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM "); + queryStrBldr.append(getEntityName(ctx)); + queryStrBldr.append(" a"); + List params = docFilter.buildWhereForSearch(queryStrBldr); //TODO: add tenant id emf = getEntityManagerFactory(); em = emf.createEntityManager(); - String queryStr = strBld.toString(); //for debugging + String queryStr = queryStrBldr.toString(); //for debugging Query q = em.createQuery(queryStr); - //TODO: add tenant id - String where = docFilter.getWhereClause(); - if ((null != where) && (where.length() > 0)) { - strBld.append(where); + //bind parameters + for(DocumentFilter.ParamBinding p : params) { + q.setParameter(p.getName(), p.getValue()); } if (docFilter.getOffset() > 0) { q.setFirstResult(docFilter.getOffset());