Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Apply criteria to a record

    Given a Criteria or AdvancedCriteria object and a Record (or a Map in server side code), how can I see if the Record (Map) values match the Criteria? I don't see anything like that in the API, but that logic must exist somewhere on the client side at least, to handle client side filtering. How can I leverage it in custom code to check if a record's values would pass a set of criteria?

    #2
    On the server, the API is Evaluator.valuesMatchCriteria().

    On the client, there's a documented SmartClient-level API DataSource.applyFilter(), but this hasn't been wrapped for SmartGWT for various reasons, but it could be called easily via JSNI.

    Comment


      #3
      Thanks. The server side Evaluator looks like just what I need. But how can I create a server side AdvancedCriteria object from a serialized String I've saved from a FilterBuilder.

      On the client side I'm using AdvancedCriteria.getJsObj() and then encoding that with JSON.encode() and decoding it again on the client side with JSON.decode().

      How can I use that same String on the server side to create a server side AdvancedCriteria object?

      Comment


        #4
        The most straightforward way to do this is to decode the string client-side and submit it to the server as part of a "fetch" operation.

        It's unclear in what use case this would be a problem, but if it is, then you'd need to use a server-side JSON decoder and traverse the provided structure creating the corresponding server-side AdvancedCriteria objects.

        Comment


          #5
          Our use case is this. Certain users are only allowed to see a subset of the records in a number of different files. We already have our own Role based security system in place.

          So we thought a good way to handle this would be to use a FilterBuilder to define the criteria for the records that should be exposed to each role (it can vary by role and datasource) and keep that in another database table keyed to data source and role.

          Then we can intercept all DSRequests on the server side (we already use a subclass of SQLDataSource) and add the saved criteria to whatever criteria may already be in the DSRequest. We thought that centralizing that logic on the server side made better since than trying to do it client side since these data sources are used in a variety of contexts and different UI components.

          Is there a better way of handling this type of requirement?

          Comment


            #6
            That makes sense and is a good argument for a server-side API such as a "new AdvancedCriteria(jsonString)" as well as perhaps a server-side equivalent of the client-side DataSource.combineCriteria() API, but with the existing APIs the best approach is the one mentioned before: parse the JSON and traverse it creating AdvancedCriteria. This would be a valid Feature Sponsorship however, and it would also be something where you could submit a working implementation and we'd roll it into the product for you.

            Comment


              #7
              This turned out to be relatively easy, with a little help from ObjectMapper at http://jackson.codehaus.org. I'll be happy to post the code once it's all working.

              The problem I'm running into is when the original criteria in the request is already a combination of two criteria and then I wrap that in an "and" condition with my role-based criteria.

              I'm passing this Map to Evaluator.parseAdvancedCriteria() ...
              Code:
              (java.util.HashMap<K,V>) 
              {
              	criteria=[
              			{
              				criteria=[{fieldName=RetailOrdered, operator=greaterThan, value=1000}], 
              				operator=and, 
              				_constructor=AdvancedCriteria
              			}, 
              			{
              				operator=and, 
              				criteria=[
              					{fieldName=HVEN, operator=inSet, value=[1]}, 
              					{fieldName=HCLO, operator=notEqual, value=true}
              					], 
              				_constructor=AdvancedCriteria
              			}
              	], 
              	operator=and, 
              	_constructor=AdvancedCriteria
              }
              ... and getting back this AdvancedCriteria object.
              Code:
              AdvancedCriteria:[and:[and:[{RetailOrdered greaterThan 1000}], and:[null, {HCLO notEqual true}]]]
              When I then try to use that to setAdvancedCriteria() on the request I get this error.
              Code:
              java.lang.NullPointerException
              	at com.isomorphic.criteria.LogicalOperator.convertToMap(LogicalOperator.java:62)
              	at com.isomorphic.criteria.LogicalOperator.convertToMap(LogicalOperator.java:64)
              	at com.isomorphic.criteria.AdvancedCriteria.getCriteriaAsMap(AdvancedCriteria.java:181)
              	at com.isomorphic.datasource.DSRequest.setAdvancedCriteria(DSRequest.java:775)
              	at com.islandpacific.gui.server.customDataSource.IpDataSource.applyFilterForRole(IpDataSource.java:122)
              	at com.islandpacific.gui.server.customDataSource.IpDataSource.execute(IpDataSource.java:83)
              	at com.islandpacific.gui.server.customDataSource.PoHeaderDS.execute(PoHeaderDS.java:361)
              	at com.isomorphic.application.AppBase.executeDefaultDSOperation(AppBase.java:721)
              	at com.isomorphic.application.AppBase.executeAppOperation(AppBase.java:658)
              	at com.isomorphic.application.AppBase.execute(AppBase.java:491)
              	at com.isomorphic.datasource.DSRequest.execute(DSRequest.java:1714)
              	at com.isomorphic.servlet.IDACall.handleDSRequest(IDACall.java:199)
              	at com.islandpacific.gui.server.customDataSource.IpIDACall.handleDSRequest(IpIDACall.java:72)
              	at com.isomorphic.servlet.IDACall.processRPCTransaction(IDACall.java:156)
              	at com.islandpacific.gui.server.customDataSource.IpIDACall.processRPCTransaction(IpIDACall.java:43)
              	at com.isomorphic.servlet.IDACall.processRequest(IDACall.java:121)
              	at com.isomorphic.servlet.IDACall.doPost(IDACall.java:73)
              	at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
              	at com.isomorphic.servlet.BaseServlet.service(BaseServlet.java:152)
              	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
              	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
              	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1097)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:343)
              	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
              	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
              	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
              	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
              	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
              	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
              	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:188)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
              	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
              	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
              	at com.islandpacific.gui.security.IpConcurrentSessionFilter.doFilter(IpConcurrentSessionFilter.java:55)
              	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
              	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
              	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
              	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
              	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1088)
              	at com.isomorphic.servlet.CompressionFilter.doFilter(CompressionFilter.java:259)
              	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1088)
              	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
              	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
              	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
              	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
              	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
              	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
              	at org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:49)
              	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
              	at org.mortbay.jetty.Server.handle(Server.java:324)
              	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
              	at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
              	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:647)
              	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
              	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
              	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
              	at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
              It seems to be the inSet operator that is tripping it up. If I change the criteria for that field to operator=contains I don't get the error and the resulting WHERE clause is correct.

              Comment


                #8
                Yup, that inSet Criterion is turning into a null somehow. There's no obvious reason for this from code inspection - could you post sample code for what you're doing so we can run it and try it out? What would be ideal is just a .java file that has a void main() method so it can just be run independently.

                Comment


                  #9
                  The code that runs into the problem is pretty simple, just DSRequest.setAdvancedCriteria(Evaluator.parseAdvancedCriteria(crit))

                  crit is the HashMap I posted earlier. The rest of the code just creates that HashMap by parsing the JSON string.

                  Comment

                  Working...
                  X