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