5 Replies Latest reply: Oct 2, 2013 2:47 AM by Jonathan.Knight RSS

    EqualsFilter on cache to query the object with parameterized accessor method

    1007895

      Hi,

       

      I have the requirement to retrieve the data from cache using filters.

      My object has deep graph hierarchy as below and I have to retreive top level object from cache by comparing the loginId which is at the bottom with value.

      For that, I have used Filter AlternateIdFilter = new EqualsFilter("getChannelInfos.getChannelInfo.get(0).getCredential.getLoginId", "test");

      When I try to execute the code, coherence throwing exceptions as

      at java.lang.Thread.run(Thread.java:680) [na:1.6.0_43]

      Caused by: java.lang.RuntimeException: Missing or inaccessible method: java.util.ArrayList.get(0)()

       

      Can you please help me to fix this issue? Do I need to write any custom handlers to handle this type of code?

      Object sample

      =============

      class FICustomer{

      private ChannelInfos channelInfo;

      public ChannelInfos getChannelInfos() {

              return channelInfos;

          }

      }

       

      public class ChannelInfos

      protected List<ChannelInfo> channelInfo;

      public List<ChannelInfo> getChannelInfo() {

              if (channelInfo == null) {

                  channelInfo = new ArrayList<ChannelInfo>();

              }

              return this.channelInfo;

          }

      }

      public class ChannelInfo{

      Credential credential;

      public Credential getCredential() {

              return credential;

          }

      }

      public class Credential{

      String loginId;

      }

        • 1. Re: EqualsFilter on cache to query the object with parameterized accessor method
          Jonathan.Knight

          Hi

           

          You need to write a custom ValueExtractor to extract the LoginId value. Here is an example...

           

          import com.tangosol.io.pof.annotation.Portable;
          import com.tangosol.util.ValueExtractor;
          
          @Portable
          public class LoginIdExtractor implements ValueExtractor {
          
              public LoginIdExtractor() {
              }
          
              @Override
              public Object extract(Object value) {
                  FICustomer customer = (FICustomer) value;
                  return customer.getChannelInfos().getChannelInfo().get(0).getCredential().getLoginId();
              }
          }
          

           

          Then you can run it like this

           

          Filter AlternateIdFilter = new EqualsFilter(new LoginIdExtractor(), "test");
          

           

          I have assumed you are using POF in your cluster so the LoginIdExtractor class is annotated with @Portable and you would need to add it to your POF configuration file.

           

          If you are using POF to serialize your domain objects into the cache then you could make a more efficient extractor than the one above using POF extractors.

           

          JK

          • 2. Re: EqualsFilter on cache to query the object with parameterized accessor method
            1007895

            HI JK,

             

            Thank you much for the inputs. It is working fine now.

            But I have another question that, to improve the performance  in looking up the cache with filter key, I am thinking of addding the key to Cache Index for the above scenario.

             

            But it is not accepting and throwing error as ' missing or inaccessible method java.util.ArrayList.get(0) exception

            NamedCache cache = CacheFactory.getCache(CACHE_NAME);

                 cache.addIndex(new ChainedExtractor("getChannelInfos.getChannelInfo.get(0).getCredential.getLoginId"),false,null);

             

            Can you please provide your thoughts on how can I accomplish the above work?  Or suggest me the better approach with examples?

             

            Thanks in Advance.

            • 3. Re: EqualsFilter on cache to query the object with parameterized accessor method
              user639604

              Use the new LoginIdExtractor() you have now for cache.addIndex().

              • 4. Re: EqualsFilter on cache to query the object with parameterized accessor method
                1007895

                Thanks.It is working.

                Regarding, adding new extractor in pof config file,  I have copied all the content from coherence-pof-config.xml to my custom pof file in class path.

                And added newly written extractor in my custom POF file.

                 

                Do I need to copy the whole content from coherence JAR file or I can add just the new content?  Will coherence library can merge the contents (coherence JAR file POF config +  custom POF config file) during execution?

                 

                Thanks.

                • 5. Re: EqualsFilter on cache to query the object with parameterized accessor method
                  Jonathan.Knight

                  Hi,

                   

                  A couple of points on the posts above.

                   

                  1. If you use the LoginIdExtractor for an Index you will need to add equals() and hashCode() methods to the class otherwise Coherence will not be able to match the extractor when in a Filter to the Index.

                  import com.tangosol.io.pof.annotation.Portable; 
                  import com.tangosol.util.ValueExtractor; 
                  
                  @Portable 
                  public class LoginIdExtractor implements ValueExtractor { 
                  
                      public LoginIdExtractor() { 
                      } 
                  
                      @Override 
                      public Object extract(Object value) { 
                          FICustomer customer = (FICustomer) value; 
                          return customer.getChannelInfos().getChannelInfo().get(0).getCredential().getLoginId(); 
                      }
                  
                      @Override
                      public boolean equals(Object obj)
                      {
                          return obj.getClass().equals(LoginIdExtractor.class);
                      }
                  
                      @Override
                      public int hashCode()
                      {
                          return LoginIdExtractor.class.hashCode();
                      }
                  } 
                  

                   

                  There is no state in the class so the equals() and hashCode() methods are very simple.

                   

                  2. Regarding copying all of the contents of the coherence-pof-config.xml into your POF configuration - this is wrong and not how you do it. You just need to include the Coherence configuration inside your configuration like this

                   

                  <pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
                    xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config
                    coherence-pof-config.xsd">
                    <user-type-list>
                      <include>coherence-pof-config.xml</include>
                  
                      <user-type>
                        <type-id>1001</type-id>
                        <class-name>LoginIdExtractor</class-name>
                      </user-type>
                    </user-type-list>
                  </pof-config>
                  

                   

                  You can see on line 6 the <include> element that includes the coherence-pof-config.xml file. You can have multiple include elements if you want to include other POF configuration files.

                   

                  3. There is a way to use a ReflectionExtractor and pass parameters to the method instead of using custom extractors. As I said though, it is more efficient to use POF extractors as you will not be deserializing everything in the cache.

                  In your case the methods you want to chain together are getChannelInfos.getChannelInfo.get(0).getCredential.getLoginId


                  As you have seen trying to do that in a single String breaks as the get(0) does not work.

                   

                  You will see that ReflectionExtractor has a constructor that takes both the method name and an array of parameters

                   

                  public ReflectionExtractor(String sMethod, Object[] aoParam)
                  

                   

                  So to use this in your case you can combine the ChainedExtractor and ReflectionExtractor to get what you want

                   

                  ValueExtractor extractor = new ChainedExtractor(
                          new ValueExtractor[]{
                                  new ChainedExtractor("getChannelInfos.getChannelInfo"),
                                  new ReflectionExtractor("get", new Object[]{0}),
                                  new ChainedExtractor("getCredential.getLoginId"),
                          }
                  );
                  
                  cache.addIndex(extractor, false, null);
                  
                  Filter filter = new EqualsFilter(extractor, "test");
                  
                  Set entries = cache.entrySet(filter);
                  

                   

                  There is a constructor for ChainedExtractor that takes an array of ValueExtractor instances to  be chained together so we use this as our main extractor. In the array of extractors we first use a ChainedExtractor to extract the result of getChannelInfos.getChannelInfo then we use a ReflectionExtractor to extract get(0) by specifying that the method name is get and the Object array of parameters just contains the single 0 for the parameter to pass to the get method. Finally we have another ChainedExtractor for the rest of the methods getCredential.getLoginId

                   

                  JK