View Javadoc
1   /**
2    * This file Copyright (c) 2017 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.ui.framework.ioc;
35  
36  import info.magnolia.ui.api.app.AppContext;
37  import info.magnolia.ui.api.app.SubAppContext;
38  
39  import java.io.Serializable;
40  import java.util.Arrays;
41  import java.util.Collections;
42  import java.util.List;
43  import java.util.Objects;
44  
45  import com.google.common.collect.ImmutableList;
46  import com.vaadin.ui.UI;
47  
48  /**
49   * A simple abstraction for the UI context identification. Capable of presenting
50   * itself as a string (easy to use as a hash-map key), provides a related
51   * {@link com.google.inject.BindingAnnotation} and provides a list
52   * of the keys that are more 'general' than the current.
53   *
54   * @see CurrentUiContextReference
55   * @see SessionStore
56   * @see UiScopes
57   */
58  public interface UiContextReference extends Serializable {
59  
60      /**
61       * Get String representation of UI context ref; useful
62       * when the reference needs to be used as a key in a hash map
63       * (e.g. in {@link BeanStore}).
64       */
65      String asString();
66  
67      /**
68       * Get {@link UiContextAnnotation} which corresponds to
69       * this UI context reference. Such annotation is also a
70       * {@link com.google.inject.BindingAnnotation} used by Guice.
71       */
72      UiContextAnnotation getAnnotation();
73  
74      /**
75       * Get all the ('broader') references that can be resolved from
76       * the current one.
77       */
78      default List<UiContextReference> getParentReferences() {
79          return Collections.emptyList();
80      }
81  
82      // UI context reference factory methods
83  
84      static UiContextReference ofUi(UI ui) {
85          return new UiContextReferenceImpl(ui) {
86              @Override
87              public UiContextAnnotation getAnnotation() {
88                  return UiAnnotations.forAdmincentral();
89              }
90          };
91      }
92  
93      static UiContextReference ofCurrentUi() {
94          return new UiContextReferenceImpl() {
95              @Override
96              public UiContextAnnotation getAnnotation() {
97                  return UiAnnotations.forAdmincentral();
98              }
99          };
100     }
101 
102     static UiContextReference ofApp(AppContext appContext) {
103         return new AppContextReference(appContext);
104     }
105 
106     static UiContextReference ofSubApp(SubAppContext subAppContext) {
107         return new SubAppContextReference(subAppContext);
108     }
109 
110     static UiContextReference ofView(String viewId, UiContextReference parentKey) {
111         return new ViewContextReference(viewId, parentKey);
112     }
113 
114     static UiContextReference genericSubAppContextReference() {
115         return new UiContextReferenceImpl() {
116 
117             @Override
118             public UiContextAnnotation getAnnotation() {
119                 return UiAnnotations.forSubApps();
120             }
121 
122             @Override
123             public List<UiContextReference> getParentReferences() {
124                 final UiContextReference genericAppContextKey = genericAppContextReference();
125                 return ImmutableList.<UiContextReference>builder().add(genericAppContextKey).addAll(genericAppContextKey.getParentReferences()).build();
126             }
127         };
128     }
129 
130     static UiContextReference genericAppContextReference() {
131         return new UiContextReferenceImpl() {
132             @Override
133             public UiContextAnnotation getAnnotation() {
134                 return UiAnnotations.forApps();
135             }
136 
137             @Override
138             public List<UiContextReference> getParentReferences() {
139                 return Arrays.asList(UiContextReference.ofCurrentUi());
140             }
141         };
142     }
143 
144     static UiContextReference genericViewContextRefence() {
145         return new UiContextReferenceImpl() {
146             @Override
147             public UiContextAnnotation getAnnotation() {
148                 return UiAnnotations.forViews();
149             }
150 
151             @Override
152             public List<UiContextReference> getParentReferences() {
153                 return Collections.emptyList();
154             }
155         };
156     }
157 
158     // Implementations of the UI context keys
159 
160     /**
161      * App specific UI context reference.
162      */
163     class AppContextReference extends UiContextReferenceImpl {
164         private final AppContext appContext;
165 
166         AppContextReference(AppContext appContext) {
167             this.appContext = appContext;
168         }
169 
170         @Override
171         String getScopeId() {
172             return String.format("%s:%s", appName(), this.appContext.hashCode());
173         }
174 
175         private String appName() {
176             return this.appContext.getName();
177         }
178 
179         @Override
180         public UiContextAnnotation getAnnotation() {
181             return UiAnnotations.forApp(appName());
182         }
183 
184         @Override
185         public List<UiContextReference> getParentReferences() {
186             return Arrays.asList(genericAppContextReference(), UiContextReference.ofCurrentUi());
187         }
188     }
189 
190     /**
191      * Sub-app specific UI context reference.
192      */
193     class SubAppContextReference extends UiContextReferenceImpl {
194 
195         private final SubAppContext subAppContext;
196 
197         SubAppContextReference(SubAppContext subAppContext) {
198             this.subAppContext = subAppContext;
199         }
200 
201         @Override
202         protected String getScopeId() {
203             return String.format("%s:%s:%s", appName(), subAppName(), subAppContext.hashCode());
204         }
205 
206         private String subAppName() {
207             return subAppContext.getSubAppDescriptor().getName();
208         }
209 
210         private String appName() {
211             return subAppContext.getAppContext().getName();
212         }
213 
214         @Override
215         public UiContextAnnotation getAnnotation() {
216             return UiAnnotations.forSubApp(appName(), subAppName());
217         }
218 
219         @Override
220         public List<UiContextReference> getParentReferences() {
221             final UiContextReference appContextKey = UiContextReference.ofApp(this.subAppContext.getAppContext());
222             return ImmutableList.<UiContextReference>builder().add(genericSubAppContextReference()).add(appContextKey).addAll(appContextKey.getParentReferences()).build();
223         }
224     }
225 
226     /**
227      * View-specific UI context reference implementation.
228      */
229     class ViewContextReference extends UiContextReferenceImpl {
230 
231         private final String viewId;
232         private final UiContextReference parentKey;
233 
234         ViewContextReference(String viewId, UiContextReference parentKey) {
235             this.viewId = viewId;
236             this.parentKey = parentKey;
237         }
238 
239         @Override
240         String getScopeId() {
241             return viewId;
242         }
243 
244         @Override
245         public UiContextAnnotation getAnnotation() {
246             return new ViewImpl(viewId);
247         }
248 
249         @Override
250         public List<UiContextReference> getParentReferences() {
251             return ImmutableList.<UiContextReference>builder().add(genericViewContextRefence()).add(parentKey).addAll(parentKey.getParentReferences()).build();
252         }
253     }
254 
255     /**
256      * Base {@link UiContextReference} implementation.
257      */
258     abstract class UiContextReferenceImpl implements UiContextReference {
259 
260         private final String uiId;
261 
262         UiContextReferenceImpl(UI ui) {
263             this.uiId = ui.getEmbedId();
264         }
265 
266         UiContextReferenceImpl() {
267             this(UI.getCurrent());
268         }
269 
270         @Override
271         public String asString() {
272             return String.format("%s:%s", getUiInstancePrefix(), getScopeId());
273         }
274 
275         String getUiInstancePrefix() {
276             return String.format("%s", uiId);
277         }
278 
279         String getScopeId() {
280             return "";
281         }
282 
283         @Override
284         public boolean equals(Object o) {
285             if (this == o) return true;
286             if (!(o instanceof UiContextReference)) return false;
287             return Objects.equals(this.asString(), ((UiContextReference) o).asString());
288         }
289 
290         @Override
291         public int hashCode() {
292             return Objects.hashCode(this.asString());
293         }
294 
295         @Override
296         public String toString() {
297             return asString();
298         }
299     }
300 }