Skip to contentMethod: lambda$dispose$1(NamedCallback)
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.ToString;
38: import lombok.experimental.Delegate;
39: import lombok.extern.slf4j.Slf4j;
40:
41: /***************************************************************************************************************************************************************
42: *
43: * A default implementation of {@link PresentationModel}.
44: *
45: * @author Fabrizio Giudici
46: *
47: **************************************************************************************************************************************************************/
48: @ToString(exclude = {"as", "pcs", "mls"}) @Slf4j @SuppressWarnings("this-escape")
49: public class DefaultPresentationModel implements PresentationModel
50: {
51: @Nonnull
52: private final Object owner;
53:
54: @Delegate
55: private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
56:
57: @Delegate
58: private final MutableListenerSupport mls = new MutableListenerSupport(pcs);
59:
60: private final As as;
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: * {@inheritDoc}
73: **********************************************************************************************************************************************************/
74: @Override @Nonnull
75: public <T> T as (@Nonnull final Class<? extends T> roleType)
76: {
77: return maybeAs(roleType).orElseThrow(() -> new AsException(roleType));
78: }
79:
80: /***********************************************************************************************************************************************************
81: * {@inheritDoc}
82: **********************************************************************************************************************************************************/
83: @SuppressWarnings("ConstantValue")
84: @Override @Nonnull
85: public <T> Optional<T> maybeAs (@Nonnull final Class<? extends T> roleType)
86: {
87: // Undocumented feature: for instance Zephyr needs to fire property events
88: if (roleType.equals(PropertyChangeSupport.class))
89: {
90: return Optional.of(roleType.cast(pcs));
91: }
92:
93: final Optional<T> t = as.maybeAs(roleType);
94:
95: if (t.isPresent())
96: {
97: return t;
98: }
99:
100: if (owner instanceof As)
101: {
102: try
103: {
104: final var role = ((As)owner).as(roleType);
105:
106: if (role != null) // do check it for improper implementations or partial mocks
107: {
108: return Optional.of(role);
109: }
110: }
111: catch (AsException ignore)
112: {
113: // fallback
114: }
115: }
116:
117: return Optional.empty();
118: }
119:
120: /***********************************************************************************************************************************************************
121: * {@inheritDoc}
122: **********************************************************************************************************************************************************/
123: @Override @Nonnull
124: public <T> Collection<T> asMany (@Nonnull final Class<? extends T> roleType)
125: {
126: final Collection<T> result = as.asMany(roleType);
127:
128: // The problem here is that we want only to add local roles in owner; but calling owner.as() will also
129: // find again the global roles that were discovered by AsSupport.
130: if (roleType.isAssignableFrom(owner.getClass()))
131: {
132: result.add(roleType.cast(owner));
133: }
134:
135: if (owner instanceof As)
136: {
137: result.addAll(((As)owner).asMany(roleType));
138: }
139:
140: return result;
141: }
142:
143: /***********************************************************************************************************************************************************
144: * {@inheritDoc}
145: **********************************************************************************************************************************************************/
146: @Override
147: public void dispose()
148: {
149: for (final var listener : pcs.getPropertyChangeListeners().clone())
150: {
151: pcs.removePropertyChangeListener(listener);
152: }
153:
154: mls.removeAllListeners();
155: asMany(NamedCallback.class).stream()
156: .filter(c -> c.getName().equals(CALLBACK_DISPOSE))
157: .forEach(callback -> wrap(callback, "While calling 'dispose' callbacks"));
158: }
159:
160: /***********************************************************************************************************************************************************
161: *
162: **********************************************************************************************************************************************************/
163: private static void wrap (@Nonnull final Callback callback, @Nonnull final String logMessage)
164: {
165: try
166: {
167: callback.call();
168: }
169: catch (Throwable t)
170: {
171: log.error(logMessage, t);
172: }
173: }
174: }