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 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/thesefoolishthings-src
22 * git clone https://github.com/tidalwave-it/thesefoolishthings-src
23 *
24 * *************************************************************************************************************************************************************
25 */
26 package it.tidalwave.role.ui.spi;
27
28 import javax.annotation.Nonnull;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.List;
32 import it.tidalwave.util.As;
33 import it.tidalwave.util.RoleFactory;
34 import it.tidalwave.util.Task;
35 import it.tidalwave.util.spi.SimpleFinderSupport;
36 import it.tidalwave.role.SimpleComposite;
37 import it.tidalwave.role.impl.ContextSnapshot;
38 import it.tidalwave.role.ui.Presentable;
39 import it.tidalwave.role.ui.PresentationModel;
40 import it.tidalwave.role.ui.PresentationModelFactory;
41 import lombok.RequiredArgsConstructor;
42 import lombok.extern.slf4j.Slf4j;
43 import static java.util.Collections.emptyList;
44 import static java.util.stream.Collectors.*;
45 import static it.tidalwave.util.ShortNames.*;
46 import static it.tidalwave.role.SimpleComposite._SimpleComposite_;
47
48 /***************************************************************************************************************************************************************
49 *
50 * An implementation of {@link Presentable} for datum instances having the {@link SimpleComposite} role.
51 *
52 * @stereotype Role
53 *
54 * @author Fabrizio Giudici
55 *
56 **************************************************************************************************************************************************************/
57 @Slf4j
58 public class SimpleCompositePresentable implements Presentable
59 {
60 private static final As.Type<SimpleComposite<As>> _SimpleCompositeOfAs_ = As.type(_SimpleComposite_);
61
62 @RequiredArgsConstructor
63 static class SCPFinder extends SimpleFinderSupport<PresentationModel>
64 {
65 // private static final long serialVersionUID = -3235827383866946732L;
66
67 @Nonnull
68 private final SimpleCompositePresentable scp;
69
70 @Nonnull
71 private final Collection<Object> roles;
72
73 public SCPFinder (@Nonnull final SCPFinder other, @Nonnull final Object override)
74 {
75 super(other, override);
76 final var source = getSource(SCPFinder.class, other, override);
77 this.scp = source.scp;
78 this.roles = source.roles;
79 }
80
81 @Override @Nonnull
82 protected List<PresentationModel> computeResults()
83 {
84 return scp.contextSnapshot.runWithContexts(new Task<>()
85 {
86 @Override @Nonnull
87 public List<PresentationModel> run()
88 {
89 final List<As> children = scp.datum.maybeAs(_SimpleComposite_)
90 .map(c -> c.findChildren().results()).orElse(emptyList());
91 return children.stream()
92 .map(child -> child.maybeAs(_Presentable_)
93 .orElseGet(() -> new SimpleCompositePresentable(child)))
94 .map(presentable -> presentable.createPresentationModel(roles))
95 .collect(toList());
96 }
97 });
98 }
99 }
100
101 private static final long serialVersionUID = 324646965695684L;
102
103 @Nonnull
104 private final As datum;
105
106 // This is not @Injected to avoid a dependency on Spring AOP
107 @Nonnull
108 private final PresentationModelFactory defaultPresentationModelFactory;
109
110 private final ContextSnapshot contextSnapshot;
111
112 /***********************************************************************************************************************************************************
113 * @param datum the owner
114 **********************************************************************************************************************************************************/
115 public SimpleCompositePresentable (@Nonnull final As datum)
116 {
117 this(datum, new DefaultPresentationModelFactory());
118 }
119
120 /***********************************************************************************************************************************************************
121 * @param datum the owner
122 * @param defaultPresentationModelFactory the {@code PresentationModelFactory}
123 **********************************************************************************************************************************************************/
124 public SimpleCompositePresentable (@Nonnull final As datum,
125 @Nonnull final PresentationModelFactory defaultPresentationModelFactory)
126 {
127 this.datum = datum;
128 this.defaultPresentationModelFactory = defaultPresentationModelFactory;
129 contextSnapshot = new ContextSnapshot(datum);
130 }
131
132 /***********************************************************************************************************************************************************
133 * {@inheritDoc}
134 **********************************************************************************************************************************************************/
135 @Override @Nonnull
136 public PresentationModel createPresentationModel (@Nonnull final Collection<Object> roles)
137 {
138 return internalCreatePresentationModel(datum, roles);
139 }
140
141 /***********************************************************************************************************************************************************
142 *
143 **********************************************************************************************************************************************************/
144 @Nonnull
145 private PresentationModel internalCreatePresentationModel (@Nonnull final As datum,
146 @Nonnull final Collection<Object> roles)
147 {
148 final var pmFinder = new SCPFinder(this, roles);
149
150 return contextSnapshot.runWithContexts(new Task<>()
151 {
152 @Override @Nonnull
153 public PresentationModel run()
154 {
155 final var r = resolveRoles(datum, roles);
156
157 if (datum.maybeAs(_SimpleComposite_).isPresent())
158 {
159 r.add(SimpleComposite.of(pmFinder));
160 }
161
162 log.trace(">>>> r for {}: {}", shortId(datum), shortIds(r));
163
164 return defaultPresentationModelFactory.createPresentationModel(datum, r);
165 }
166 });
167 }
168
169 /***********************************************************************************************************************************************************
170 *
171 **********************************************************************************************************************************************************/
172 @Nonnull
173 private List<Object> resolveRoles (@Nonnull final As datum, @Nonnull final Collection<Object> roles)
174 {
175 final List<Object> r = new ArrayList<>();
176
177 for (final var roleOrFactory : roles)
178 {
179 if (roleOrFactory instanceof RoleFactory)
180 {
181 r.add(((RoleFactory<As>)roleOrFactory).createRoleFor(datum));
182 }
183 else
184 {
185 r.add(roleOrFactory);
186 }
187 }
188
189 return r;
190 }
191 }