View Javadoc
1   /**
2    * This file Copyright (c) 2017-2018 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  import info.magnolia.ui.framework.ioc.DatasourceComponent.DatasourceComponentImpl;
39  
40  import java.io.Serializable;
41  import java.util.ArrayList;
42  import java.util.Arrays;
43  import java.util.Collections;
44  import java.util.List;
45  import java.util.Objects;
46  import java.util.Optional;
47  
48  import com.google.common.collect.ImmutableList;
49  import com.vaadin.ui.UI;
50  
51  /**
52   * A simple abstraction for the UI context identification. Useful in the two following scenarios:
53   * <p>
54   * Used by {@link SessionStore} as the key of a {@link BeanStore} containing
55   * scoped objects (see {@link UiContextReference#asString() method}).
56   * </p>
57   * <p>
58   * Helps to resolve the {@link com.google.inject.BindingAnnotation Guice Binding Annotation} corresponding
59   * to the UI context, which provides access to context-specific type bindings
60   * (orchestrated by e.g. {@link UiContextApplyingProvider}).
61   * </p>
62   * <p>
63   * Also provides a list of the keys that are more 'general' than the current.  
64   * </p>
65   *
66   * @see UiContextApplyingProvider
67   * @see CurrentUiContextReference
68   * @see SessionStore
69   * @see UiScopes
70   */
71  public interface UiContextReference extends Serializable {
72  
73      /**
74       * Get String representation of UI context ref; useful
75       * when the reference needs to be used as a key in a hash map
76       * (e.g. in {@link BeanStore}).
77       */
78      String asString();
79  
80      /**
81       * Get {@link UiContextAnnotation} which corresponds to
82       * this UI context reference. Such annotation is also a
83       * {@link com.google.inject.BindingAnnotation} used by Guice.
84       */
85      UiContextAnnotation getAnnotation();
86  
87      /**
88       * Get all the ('broader') references that can be resolved from
89       * the current one.
90       */
91      default List<UiContextReference> getParentReferences() {
92          return Collections.emptyList();
93      }
94  
95      default Optional<UiContextReference> getDirectParentReference() {
96          return Optional.empty();
97      }
98  
99      // UI context reference factory methods
100 
101     static UiContextReference ofUi(UI ui) {
102         return new UiContextReferenceImpl(ui) {
103             @Override
104             public UiContextAnnotation getAnnotation() {
105                 return UiAnnotations.forAdmincentral();
106             }
107         };
108     }
109 
110     static UiContextReference ofM5Admincentral() {
111         return new UiContextReferenceImpl() {
112             @Override
113             public UiContextAnnotation getAnnotation() {
114                 return UiAnnotations.forM5Admincentral();
115             }
116 
117             @Override
118             public List<UiContextReference> getParentReferences() {
119                 return Arrays.asList(new UiContextReferenceImpl() {
120                     @Override
121                     public UiContextAnnotation getAnnotation() {
122                         return UiAnnotations.forAdmincentral();
123                     }
124                 });
125             }
126         };
127     }
128 
129     static UiContextReference ofCurrentUi() {
130         return new UiContextReferenceImpl() {
131             @Override
132             public UiContextAnnotation getAnnotation() {
133                 return UiAnnotations.forAdmincentral();
134             }
135         };
136     }
137 
138     /**
139      * Creates a UI context reference bound to a concrete instance of an app.
140      * All the app scoped objects relevant to that app will be resolvable through
141      * this reference.
142      *
143      * @param appContext concrete instance of a app context
144      * @return ui context reference bound to the app instance
145      */
146     static UiContextReference ofApp(AppContext appContext) {
147         return new AppContextReference(appContext);
148     }
149 
150     /**
151      * Creates a UI context reference bound to a concrete instance of a sub-app.
152      * All the scoped objects relevant to that sub-app will be resolvable through
153      * this reference.
154      *
155      * @param subAppContext concrete instance of a sub-app context
156      * @return ui context reference bound to sub-app instance
157      */
158     static UiContextReference ofSubApp(SubAppContext subAppContext) {
159         return new SubAppContextReference(subAppContext);
160     }
161 
162     static UiContextReferenceolia/ui/framework/ioc/UiContextReference.html#UiContextReference">UiContextReference ofView(String viewId, UiContextReference parentKey) {
163         return new ViewContextReference(viewId, parentKey);
164     }
165 
166     static UiContextReference ofDatasourceComponent(String datasourceId) {
167         return new DatasourceComponentContextReference(datasourceId);
168     }
169 
170     static UiContextReference genericSubAppContextReference() {
171         return new UiContextReferenceImpl() {
172 
173             @Override
174             public UiContextAnnotation getAnnotation() {
175                 return UiAnnotations.forSubApps();
176             }
177         };
178     }
179 
180     static UiContextReference genericAppContextReference() {
181         return new UiContextReferenceImpl() {
182             @Override
183             public UiContextAnnotation getAnnotation() {
184                 return UiAnnotations.forApps();
185             }
186         };
187     }
188 
189     static UiContextReference genericViewContextReference() {
190         return new UiContextReferenceImpl() {
191             @Override
192             public UiContextAnnotation getAnnotation() {
193                 return UiAnnotations.forViews();
194             }
195         };
196     }
197 
198     // Implementations of the UI context keys
199 
200     /**
201      * App specific UI context reference.
202      */
203     class AppContextReference extends UiContextReferenceImpl {
204         private final AppContext appContext;
205 
206         AppContextReference(AppContext appContext) {
207             this.appContext = appContext;
208         }
209 
210         @Override
211         String getScopeId() {
212             return String.join(":", appName(), String.valueOf(appContext.hashCode()));
213         }
214 
215         private String appName() {
216             return this.appContext.getName();
217         }
218 
219         @Override
220         public Optional<UiContextReference> getDirectParentReference() {
221             return Optional.of(UiContextReference.ofCurrentUi());
222         }
223 
224         @Override
225         public UiContextAnnotation getAnnotation() {
226             return UiAnnotations.forApp(appName());
227         }
228 
229         @Override
230         public List<UiContextReference> getParentReferences() {
231             final List<UiContextReference> parentReferenceList = new ArrayList<>();
232             parentReferenceList.add(genericAppContextReference());
233             if (AdmincentralFlavour.get().isM5()) {
234                 parentReferenceList.add(UiContextReference.ofM5Admincentral());
235             }
236             parentReferenceList.add(UiContextReference.ofCurrentUi());
237             return parentReferenceList;
238         }
239     }
240 
241     /**
242      * Sub-app specific UI context reference.
243      */
244     class SubAppContextReference extends UiContextReferenceImpl {
245 
246         private final SubAppContext subAppContext;
247 
248         SubAppContextReference(SubAppContext subAppContext) {
249             this.subAppContext = subAppContext;
250         }
251 
252         @Override
253         protected String getScopeId() {
254             return String.join(":", appName(), subAppName(), String.valueOf(subAppContext.hashCode()));
255         }
256 
257         private String subAppName() {
258             return subAppContext.getSubAppDescriptor().getName();
259         }
260 
261         private String appName() {
262             return subAppContext.getAppContext().getName();
263         }
264 
265         @Override
266         public Optional<UiContextReference> getDirectParentReference() {
267             return Optional.of(UiContextReference.ofApp(subAppContext.getAppContext()));
268         }
269 
270         @Override
271         public UiContextAnnotation getAnnotation() {
272             return UiAnnotations.forSubApp(appName(), subAppName());
273         }
274 
275         @Override
276         public List<UiContextReference> getParentReferences() {
277             final UiContextReference appContextKey = UiContextReference.ofApp(this.subAppContext.getAppContext());
278             return ImmutableList.<UiContextReference>builder().add(genericSubAppContextReference()).add(appContextKey).addAll(appContextKey.getParentReferences()).build();
279         }
280     }
281 
282     /**
283      * View-specific UI context reference implementation.
284      */
285     class ViewContextReference extends UiContextReferenceImpl {
286 
287         private final String viewId;
288         private final UiContextReference parentUiContextReference;
289 
290         ViewContextReference(String viewId, UiContextReference parentKey) {
291             this.viewId = viewId;
292             this.parentUiContextReference = parentKey;
293         }
294 
295         @Override
296         String getScopeId() {
297             return viewId;
298         }
299 
300         @Override
301         public UiContextAnnotation getAnnotation() {
302             return new ViewImpl(viewId);
303         }
304 
305         @Override
306         public Optional<UiContextReference> getDirectParentReference() {
307             return Optional.of(parentUiContextReference);
308         }
309 
310         @Override
311         public List<UiContextReference> getParentReferences() {
312             return ImmutableList.<UiContextReference>builder().add(genericViewContextReference()).add(parentUiContextReference).addAll(parentUiContextReference.getParentReferences()).build();
313         }
314 
315         @Override
316         public String asString() {
317             return String.join(":", parentUiContextReference.asString(), getScopeId());
318         }
319     }
320 
321     /**
322      * Datasource-specific component reference implementation.
323      */
324     class DatasourceComponentContextReference extends UiContextReferenceImpl {
325 
326         private final String datasourceId;
327 
328         DatasourceComponentContextReference(String datasourceId) {
329             this.datasourceId = datasourceId;
330         }
331 
332         @Override
333         public UiContextAnnotation getAnnotation() {
334             return new DatasourceComponentImpl(datasourceId);
335         }
336     }
337 
338     /**
339      * Base {@link UiContextReference} implementation.
340      */
341     abstract class UiContextReferenceImpl implements UiContextReference {
342 
343         private final String uiId;
344 
345         UiContextReferenceImpl(UI ui) {
346             this.uiId = String.format("%s:%d", ui.getEmbedId(), ui.getUIId());
347         }
348 
349         UiContextReferenceImpl() {
350             this(UI.getCurrent());
351         }
352 
353         @Override
354         public String asString() {
355             return String.join(":", getUiInstancePrefix(), getScopeId());
356         }
357 
358         String getUiInstancePrefix() {
359             return uiId;
360         }
361 
362         String getScopeId() {
363             return "";
364         }
365 
366         @Override
367         public boolean equals(Object o) {
368             if (this == o) return true;
369             if (!(o instanceof UiContextReference)) return false;
370             return Objects.equals(this.asString(), ((UiContextReference) o).asString());
371         }
372 
373         @Override
374         public int hashCode() {
375             return Objects.hashCode(this.asString());
376         }
377 
378         @Override
379         public String toString() {
380             return asString();
381         }
382     }
383 }