Skip to contentMethod: maybeAs(Class)
1: /*
2: * *********************************************************************************************************************
3: *
4: * TheseFoolishThings: Miscellaneous utilities
5: * http://tidalwave.it/projects/thesefoolishthings
6: *
7: * Copyright (C) 2009 - 2024 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *********************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
12: * the License. You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
17: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
18: * specific language governing permissions and limitations under the License.
19: *
20: * *********************************************************************************************************************
21: *
22: * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
23: * git clone https://github.com/tidalwave-it/thesefoolishthings-src
24: *
25: * *********************************************************************************************************************
26: */
27: package it.tidalwave.role.ui.impl;
28:
29: import javax.annotation.Nonnull;
30: import java.beans.PropertyChangeSupport;
31: import java.util.Collection;
32: import java.util.Optional;
33: import it.tidalwave.util.As;
34: import it.tidalwave.util.AsException;
35: import it.tidalwave.util.Callback;
36: import it.tidalwave.util.NamedCallback;
37: import it.tidalwave.role.ui.PresentationModel;
38: import lombok.ToString;
39: import lombok.experimental.Delegate;
40: import lombok.extern.slf4j.Slf4j;
41:
42: /***********************************************************************************************************************
43: *
44: * A default implementation of {@link PresentationModel}.
45: *
46: * @author Fabrizio Giudici
47: *
48: **********************************************************************************************************************/
49: @ToString(exclude = {"as", "pcs"}) @Slf4j
50: public class DefaultPresentationModel implements PresentationModel
51: {
52: @Nonnull
53: private final Object owner;
54:
55: @Delegate
56: private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
57:
58: private final As as;
59:
60: /*******************************************************************************************************************
61: *
62: *
63: *
64: ******************************************************************************************************************/
65: public DefaultPresentationModel (@Nonnull final Object owner, @Nonnull final Collection<Object> roles)
66: {
67: this.owner = owner;
68: as = As.forObject(owner, roles);
69: }
70:
71: /*******************************************************************************************************************
72: *
73: * {@inheritDoc}
74: *
75: ******************************************************************************************************************/
76: @Override @Nonnull
77: public <T> T as (@Nonnull final Class<? extends T> roleType)
78: {
79: return maybeAs(roleType).orElseThrow(() -> new AsException(roleType));
80: }
81:
82: /*******************************************************************************************************************
83: *
84: * {@inheritDoc}
85: *
86: ******************************************************************************************************************/
87: @SuppressWarnings("ConstantValue")
88: @Override @Nonnull
89: public <T> Optional<T> maybeAs (@Nonnull final Class<? extends T> roleType)
90: {
91: // Undocumented feature: for instance Zephyr needs to fire property events
92:• if (roleType.equals(PropertyChangeSupport.class))
93: {
94: return Optional.of(roleType.cast(pcs));
95: }
96:
97: final Optional<T> t = as.maybeAs(roleType);
98:
99:• if (t.isPresent())
100: {
101: return t;
102: }
103:
104:• if (owner instanceof As)
105: {
106: try
107: {
108: final var role = ((As)owner).as(roleType);
109:
110:• if (role != null) // do check it for improper implementations or partial mocks
111: {
112: return Optional.of(role);
113: }
114: }
115: catch (AsException e)
116: {
117: // fallback
118: }
119: }
120:
121: return Optional.empty();
122: }
123:
124: /*******************************************************************************************************************
125: *
126: * {@inheritDoc}
127: *
128: ******************************************************************************************************************/
129: @Override @Nonnull
130: public <T> Collection<T> asMany (@Nonnull final Class<? extends T> roleType)
131: {
132: final Collection<T> result = as.asMany(roleType);
133:
134: // The problem here is that we want only to add local roles in owner; but calling owner.as() will also
135: // find again the global roles that were discovered by AsSupport.
136: if (roleType.isAssignableFrom(owner.getClass()))
137: {
138: result.add(roleType.cast(owner));
139: }
140:
141: if (owner instanceof As)
142: {
143: result.addAll(((As)owner).asMany(roleType));
144: }
145:
146: return result;
147: }
148:
149: /*******************************************************************************************************************
150: *
151: * {@inheritDoc}
152: *
153: ******************************************************************************************************************/
154: @Override
155: public void dispose()
156: {
157: for (final var listener : pcs.getPropertyChangeListeners().clone())
158: {
159: pcs.removePropertyChangeListener(listener);
160: }
161:
162: asMany(NamedCallback.class).stream()
163: .filter(c -> c.getName().equals(CALLBACK_DISPOSE))
164: .forEach(callback -> wrap(callback, "While calling 'dispose' callbacks"));
165: }
166:
167: /*******************************************************************************************************************
168: *
169: ******************************************************************************************************************/
170: private static void wrap (@Nonnull final Callback callback, @Nonnull final String logMessage)
171: {
172: try
173: {
174: callback.call();
175: }
176: catch (Throwable t)
177: {
178: log.error(logMessage, t);
179: }
180: }
181: }