Skip to contentMethod: wrap(Callback, String)
1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * SteelBlue: DCI User Interfaces
5: * http://tidalwave.it/projects/steelblue
6: *
7: * Copyright (C) 2015 - 2025 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 the License.
12: * 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 an "AS IS" BASIS, WITHOUT WARRANTIES OR
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/steelblue-src
22: * git clone https://github.com/tidalwave-it/steelblue-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.ui.core.role.impl;
27:
28: import jakarta.annotation.Nonnull;
29: import java.beans.PropertyChangeSupport;
30: import java.util.Collection;
31: import java.util.Optional;
32: import it.tidalwave.util.As;
33: import it.tidalwave.util.AsException;
34: import it.tidalwave.util.Callback;
35: import it.tidalwave.util.NamedCallback;
36: import it.tidalwave.ui.core.role.PresentationModel;
37: import lombok.Getter;
38: import lombok.Setter;
39: import lombok.experimental.Delegate;
40: import lombok.extern.slf4j.Slf4j;
41: import static it.tidalwave.util.ShortNames.shortId;
42:
43: /***************************************************************************************************************************************************************
44: *
45: * A default implementation of {@link PresentationModel}.
46: *
47: * @author Fabrizio Giudici
48: *
49: **************************************************************************************************************************************************************/
50: @Slf4j @SuppressWarnings("this-escape")
51: public class DefaultPresentationModel implements PresentationModel
52: {
53: @Getter @Setter
54: private static boolean verboseToString = Boolean.getBoolean(P_VERBOSE_TOSTRING);
55:
56: @Nonnull
57: private final Object owner;
58:
59: @Delegate
60: private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
61:
62: @Delegate
63: private final MutableListenerSupport mls = new MutableListenerSupport(pcs);
64:
65: private final As as;
66:
67: /***********************************************************************************************************************************************************
68: *
69: **********************************************************************************************************************************************************/
70: public DefaultPresentationModel (@Nonnull final Object owner, @Nonnull final Collection<Object> roles)
71: {
72: this.owner = owner;
73: as = As.forObject(owner, roles);
74: }
75:
76: /***********************************************************************************************************************************************************
77: * {@inheritDoc}
78: **********************************************************************************************************************************************************/
79: @Override @Nonnull
80: public <T> T as (@Nonnull final Class<? extends T> roleType)
81: {
82: return maybeAs(roleType).orElseThrow(() -> new AsException(roleType));
83: }
84:
85: /***********************************************************************************************************************************************************
86: * {@inheritDoc}
87: **********************************************************************************************************************************************************/
88: @SuppressWarnings("ConstantValue")
89: @Override @Nonnull
90: public <T> Optional<T> maybeAs (@Nonnull final Class<? extends T> roleType)
91: {
92: // Undocumented feature: for instance Zephyr needs to fire property events
93: if (roleType.equals(PropertyChangeSupport.class))
94: {
95: return Optional.of(roleType.cast(pcs));
96: }
97:
98: final Optional<T> t = as.maybeAs(roleType);
99:
100: if (t.isPresent())
101: {
102: return t;
103: }
104:
105: if (owner instanceof As)
106: {
107: try
108: {
109: final var role = ((As)owner).as(roleType);
110:
111: if (role != null) // do check it for improper implementations or partial mocks
112: {
113: return Optional.of(role);
114: }
115: }
116: catch (AsException ignore)
117: {
118: // fallback
119: }
120: }
121:
122: return Optional.empty();
123: }
124:
125: /***********************************************************************************************************************************************************
126: * {@inheritDoc}
127: **********************************************************************************************************************************************************/
128: @Override @Nonnull
129: public <T> Collection<T> asMany (@Nonnull final Class<? extends T> roleType)
130: {
131: final Collection<T> result = as.asMany(roleType);
132:
133: // The problem here is that we want only to add local roles in owner; but calling owner.as() will also
134: // find again the global roles that were discovered by AsSupport.
135: if (roleType.isAssignableFrom(owner.getClass()))
136: {
137: result.add(roleType.cast(owner));
138: }
139:
140: if (owner instanceof As)
141: {
142: result.addAll(((As)owner).asMany(roleType));
143: }
144:
145: return result;
146: }
147:
148: /***********************************************************************************************************************************************************
149: * {@inheritDoc}
150: **********************************************************************************************************************************************************/
151: @Override
152: public void dispose()
153: {
154: for (final var listener : pcs.getPropertyChangeListeners().clone())
155: {
156: pcs.removePropertyChangeListener(listener);
157: }
158:
159: mls.removeAllListeners();
160: asMany(NamedCallback.class).stream()
161: .filter(c -> c.getName().equals(CALLBACK_DISPOSE))
162: .forEach(callback -> wrap(callback, "While calling 'dispose' callbacks"));
163: }
164:
165: /***********************************************************************************************************************************************************
166: *
167: **********************************************************************************************************************************************************/
168: private static void wrap (@Nonnull final Callback callback, @Nonnull final String logMessage)
169: {
170: try
171: {
172: callback.call();
173: }
174: catch (Throwable t)
175: {
176: log.error(logMessage, t);
177: }
178: }
179:
180: /***********************************************************************************************************************************************************
181: * {@inheritDoc}
182: * This is unavoidably called by TreeCell renderers, even though the value is later overridden; so this method should be really fast.
183: **********************************************************************************************************************************************************/
184: @Override @Nonnull
185: public String toString()
186: {
187: return "DefaultPresentationModel(" + (verboseToString ? owner : shortId(owner)) + ")";
188: }
189: }