View Javadoc

1   /*
2    *  Copyright 2001-2013 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.beans.query;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.List;
21  
22  import org.joda.beans.Bean;
23  import org.joda.beans.BeanQuery;
24  import org.joda.beans.MetaProperty;
25  
26  /**
27   * A chained query, that allows two or more queries to be joined.
28   * <p>
29   * For example, consider a structure where class A has a property b of type B,
30   * and class B has a property c of type C. The compound query allows property
31   * c to be accessed directly from an instance of A.
32   * 
33   * @param <P>  the type of the result of the query
34   * @author Stephen Colebourne
35   */
36  public final class ChainedBeanQuery<P> implements BeanQuery<P> {
37  
38      /**
39       * The list of queries.
40       */
41      private final List<BeanQuery<? extends Bean>> chain;
42      /**
43       * The last query.
44       */
45      private final BeanQuery<P> last;
46  
47      /**
48       * Obtains a chained query from two other queries.
49       * <p>
50       * {@link MetaProperty} implements {@link BeanQuery}, so typically the parameters
51       * are in fact meta-properties.
52       * 
53       * @param <P>  the result type
54       * @param prop1  the first query, not null
55       * @param prop2  the second query, not null
56       * @return the compound query, not null
57       * @throws IllegalArgumentException if unable to obtain the meta-bean
58       */
59      public static <P> ChainedBeanQuery<P> of(BeanQuery<? extends Bean> prop1, BeanQuery<P> prop2) {
60          if (prop1 == null || prop2 == null) {
61              throw new NullPointerException("BeanQuery must not be null");
62          }
63          List<BeanQuery<? extends Bean>> list = Collections.<BeanQuery<? extends Bean>>singletonList(prop1);
64          return new ChainedBeanQuery<P>(list, prop2);
65      }
66  
67      /**
68       * Obtains a chained query from three queries.
69       * <p>
70       * {@link MetaProperty} implements {@link BeanQuery}, so typically the parameters
71       * are in fact meta-properties.
72       * 
73       * @param <P>  the result type
74       * @param prop1  the first query, not null
75       * @param prop2  the second query, not null
76       * @param prop3  the third query, not null
77       * @return the compound query, not null
78       * @throws IllegalArgumentException if unable to obtain the meta-bean
79       */
80      public static <P> ChainedBeanQuery<P> of(BeanQuery<? extends Bean> prop1, BeanQuery<? extends Bean> prop2, BeanQuery<P> prop3) {
81          if (prop1 == null || prop2 == null || prop3 == null) {
82              throw new NullPointerException("BeanQuery must not be null");
83          }
84          List<BeanQuery<? extends Bean>> list = new ArrayList<BeanQuery<? extends Bean>>();
85          list.add(prop1);
86          list.add(prop2);
87          return new ChainedBeanQuery<P>(list, prop3);
88      }
89  
90      /**
91       * Obtains a chained query from four queries.
92       * <p>
93       * {@link MetaProperty} implements {@link BeanQuery}, so typically the parameters
94       * are in fact meta-properties.
95       * 
96       * @param <P>  the result type
97       * @param prop1  the first query, not null
98       * @param prop2  the second query, not null
99       * @param prop3  the third query, not null
100      * @param prop4  the fourth query, not null
101      * @return the compound query, not null
102      * @throws IllegalArgumentException if unable to obtain the meta-bean
103      */
104     public static <P> ChainedBeanQuery<P> of(BeanQuery<? extends Bean> prop1, BeanQuery<? extends Bean> prop2, BeanQuery<? extends Bean> prop3, BeanQuery<P> prop4) {
105         if (prop1 == null || prop2 == null || prop3 == null || prop4 == null) {
106             throw new NullPointerException("BeanQuery must not be null");
107         }
108         List<BeanQuery<? extends Bean>> list = new ArrayList<BeanQuery<? extends Bean>>();
109         list.add(prop1);
110         list.add(prop2);
111         list.add(prop3);
112         return new ChainedBeanQuery<P>(list, prop4);
113     }
114 
115     //-------------------------------------------------------------------------
116     /**
117      * Restricted constructor.
118      */
119     private ChainedBeanQuery(List<BeanQuery<? extends Bean>> metaProperties, BeanQuery<P> last) {
120         this.chain = metaProperties;
121         this.last = last;
122     }
123 
124     //-----------------------------------------------------------------------
125     /**
126      * Gets the list of queries being chained.
127      * <p>
128      * {@link MetaProperty} implements {@link BeanQuery}, so typically the chain
129      * is formed from meta-properties.
130      * 
131      * @return the list of all meta-properties being chained, not null
132      */
133     public List<BeanQuery<?>> getChain() {
134         List<BeanQuery<?>> list = new ArrayList<BeanQuery<?>>(chain);
135         list.add(last);
136         return list;
137     }
138 
139     //-------------------------------------------------------------------------
140     @Override
141     public P get(Bean bean) {
142         for (BeanQuery<? extends Bean> mp : chain) {
143             bean = mp.get(bean);
144         }
145         return last.get(bean);
146     }
147 
148     //-------------------------------------------------------------------------
149     @Override
150     public String toString() {
151         StringBuilder buf = new StringBuilder(64);
152         for (BeanQuery<? extends Bean> mp : chain) {
153             buf.append(mp).append('.');
154         }
155         buf.append(last);
156         return buf.toString();
157     }
158 
159 }