ad45f304eb3cd7d0b76ffec807ec53b4bd8c3100
[dcaegen2/platform.git] / mod / designtool / designtool-web / src / main / java / org / apache / nifi / web / api / dto / DtoFactory.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Modifications to the original nifi code for the ONAP project are made
18  * available under the Apache License, Version 2.0
19  */
20 package org.apache.nifi.web.api.dto;
21
22 import org.apache.commons.codec.digest.DigestUtils;
23 import org.apache.commons.lang3.ClassUtils;
24 import org.apache.commons.lang3.StringUtils;
25 import org.apache.nifi.action.Action;
26 import org.apache.nifi.action.component.details.ComponentDetails;
27 import org.apache.nifi.action.component.details.ExtensionDetails;
28 import org.apache.nifi.action.component.details.FlowChangeExtensionDetails;
29 import org.apache.nifi.action.component.details.FlowChangeRemoteProcessGroupDetails;
30 import org.apache.nifi.action.component.details.RemoteProcessGroupDetails;
31 import org.apache.nifi.action.details.ActionDetails;
32 import org.apache.nifi.action.details.ConfigureDetails;
33 import org.apache.nifi.action.details.ConnectDetails;
34 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
35 import org.apache.nifi.action.details.FlowChangeConnectDetails;
36 import org.apache.nifi.action.details.FlowChangeMoveDetails;
37 import org.apache.nifi.action.details.FlowChangePurgeDetails;
38 import org.apache.nifi.action.details.MoveDetails;
39 import org.apache.nifi.action.details.PurgeDetails;
40 import org.apache.nifi.annotation.behavior.Restricted;
41 import org.apache.nifi.annotation.behavior.Restriction;
42 import org.apache.nifi.annotation.behavior.Stateful;
43 import org.apache.nifi.annotation.documentation.CapabilityDescription;
44 import org.apache.nifi.annotation.documentation.DeprecationNotice;
45 import org.apache.nifi.annotation.documentation.Tags;
46 import org.apache.nifi.authorization.AccessPolicy;
47 import org.apache.nifi.authorization.Authorizer;
48 import org.apache.nifi.authorization.AuthorizerCapabilityDetection;
49 import org.apache.nifi.authorization.Group;
50 import org.apache.nifi.authorization.RequestAction;
51 import org.apache.nifi.authorization.Resource;
52 import org.apache.nifi.authorization.User;
53 import org.apache.nifi.authorization.resource.Authorizable;
54 import org.apache.nifi.authorization.resource.ComponentAuthorizable;
55 import org.apache.nifi.authorization.resource.OperationAuthorizable;
56 import org.apache.nifi.authorization.user.NiFiUser;
57 import org.apache.nifi.authorization.user.NiFiUserUtils;
58 import org.apache.nifi.bundle.Bundle;
59 import org.apache.nifi.bundle.BundleCoordinate;
60 import org.apache.nifi.bundle.BundleDetails;
61 import org.apache.nifi.cluster.coordination.heartbeat.NodeHeartbeat;
62 import org.apache.nifi.cluster.coordination.node.NodeConnectionStatus;
63 import org.apache.nifi.cluster.event.NodeEvent;
64 import org.apache.nifi.cluster.manager.StatusMerger;
65 import org.apache.nifi.cluster.protocol.NodeIdentifier;
66 import org.apache.nifi.components.AllowableValue;
67 import org.apache.nifi.components.PropertyDescriptor;
68 import org.apache.nifi.components.ValidationResult;
69 import org.apache.nifi.components.state.Scope;
70 import org.apache.nifi.components.state.StateMap;
71 import org.apache.nifi.components.validation.ValidationStatus;
72 import org.apache.nifi.connectable.Connectable;
73 import org.apache.nifi.connectable.ConnectableType;
74 import org.apache.nifi.connectable.Connection;
75 import org.apache.nifi.connectable.Funnel;
76 import org.apache.nifi.connectable.Port;
77 import org.apache.nifi.connectable.Position;
78 import org.apache.nifi.controller.ActiveThreadInfo;
79 import org.apache.nifi.controller.ComponentNode;
80 import org.apache.nifi.controller.ControllerService;
81 import org.apache.nifi.controller.Counter;
82 import org.apache.nifi.controller.FlowController;
83 import org.apache.nifi.controller.ProcessorNode;
84 import org.apache.nifi.controller.ReportingTaskNode;
85 import org.apache.nifi.controller.Snippet;
86 import org.apache.nifi.controller.Template;
87 import org.apache.nifi.controller.label.Label;
88 import org.apache.nifi.controller.queue.DropFlowFileState;
89 import org.apache.nifi.controller.queue.DropFlowFileStatus;
90 import org.apache.nifi.controller.queue.FlowFileQueue;
91 import org.apache.nifi.controller.queue.FlowFileSummary;
92 import org.apache.nifi.controller.queue.ListFlowFileState;
93 import org.apache.nifi.controller.queue.ListFlowFileStatus;
94 import org.apache.nifi.controller.queue.LoadBalanceStrategy;
95 import org.apache.nifi.controller.queue.LocalQueuePartitionDiagnostics;
96 import org.apache.nifi.controller.queue.QueueDiagnostics;
97 import org.apache.nifi.controller.queue.QueueSize;
98 import org.apache.nifi.controller.queue.RemoteQueuePartitionDiagnostics;
99 import org.apache.nifi.controller.repository.FlowFileRecord;
100 import org.apache.nifi.controller.repository.claim.ContentClaim;
101 import org.apache.nifi.controller.repository.claim.ResourceClaim;
102 import org.apache.nifi.controller.service.ControllerServiceNode;
103 import org.apache.nifi.controller.service.ControllerServiceProvider;
104 import org.apache.nifi.controller.state.SortedStateUtils;
105 import org.apache.nifi.controller.status.ConnectionStatus;
106 import org.apache.nifi.controller.status.PortStatus;
107 import org.apache.nifi.controller.status.ProcessGroupStatus;
108 import org.apache.nifi.controller.status.ProcessorStatus;
109 import org.apache.nifi.controller.status.RemoteProcessGroupStatus;
110 import org.apache.nifi.controller.status.history.GarbageCollectionHistory;
111 import org.apache.nifi.controller.status.history.GarbageCollectionStatus;
112 import org.apache.nifi.diagnostics.GarbageCollection;
113 import org.apache.nifi.diagnostics.StorageUsage;
114 import org.apache.nifi.diagnostics.SystemDiagnostics;
115 import org.apache.nifi.expression.ExpressionLanguageScope;
116 import org.apache.nifi.flowfile.FlowFilePrioritizer;
117 import org.apache.nifi.flowfile.attributes.CoreAttributes;
118 import org.apache.nifi.groups.ProcessGroup;
119 import org.apache.nifi.groups.ProcessGroupCounts;
120 import org.apache.nifi.groups.RemoteProcessGroup;
121 import org.apache.nifi.groups.RemoteProcessGroupCounts;
122 import org.apache.nifi.history.History;
123 import org.apache.nifi.nar.ExtensionManager;
124 import org.apache.nifi.nar.NarClassLoadersHolder;
125 import org.apache.nifi.processor.Processor;
126 import org.apache.nifi.processor.Relationship;
127 import org.apache.nifi.provenance.lineage.ComputeLineageResult;
128 import org.apache.nifi.provenance.lineage.ComputeLineageSubmission;
129 import org.apache.nifi.provenance.lineage.LineageEdge;
130 import org.apache.nifi.provenance.lineage.LineageNode;
131 import org.apache.nifi.provenance.lineage.ProvenanceEventLineageNode;
132 import org.apache.nifi.registry.ComponentVariableRegistry;
133 import org.apache.nifi.registry.flow.FlowRegistry;
134 import org.apache.nifi.registry.flow.VersionControlInformation;
135 import org.apache.nifi.registry.flow.VersionedComponent;
136 import org.apache.nifi.registry.flow.VersionedFlowState;
137 import org.apache.nifi.registry.flow.VersionedFlowStatus;
138 import org.apache.nifi.registry.flow.diff.DifferenceType;
139 import org.apache.nifi.registry.flow.diff.FlowComparison;
140 import org.apache.nifi.registry.flow.diff.FlowDifference;
141 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedComponent;
142 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedConnection;
143 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedControllerService;
144 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedFunnel;
145 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedLabel;
146 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedPort;
147 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedProcessGroup;
148 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedProcessor;
149 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedRemoteGroupPort;
150 import org.apache.nifi.registry.flow.mapping.InstantiatedVersionedRemoteProcessGroup;
151 import org.apache.nifi.registry.variable.VariableRegistryUpdateRequest;
152 import org.apache.nifi.registry.variable.VariableRegistryUpdateStep;
153 import org.apache.nifi.remote.RemoteGroupPort;
154 import org.apache.nifi.remote.RootGroupPort;
155 import org.apache.nifi.reporting.Bulletin;
156 import org.apache.nifi.reporting.BulletinRepository;
157 import org.apache.nifi.reporting.ReportingTask;
158 import org.apache.nifi.scheduling.SchedulingStrategy;
159 import org.apache.nifi.util.FlowDifferenceFilters;
160 import org.apache.nifi.util.FormatUtils;
161 import org.apache.nifi.web.FlowModification;
162 import org.apache.nifi.web.Revision;
163 import org.apache.nifi.web.api.dto.action.ActionDTO;
164 import org.apache.nifi.web.api.dto.action.HistoryDTO;
165 import org.apache.nifi.web.api.dto.action.component.details.ComponentDetailsDTO;
166 import org.apache.nifi.web.api.dto.action.component.details.ExtensionDetailsDTO;
167 import org.apache.nifi.web.api.dto.action.component.details.RemoteProcessGroupDetailsDTO;
168 import org.apache.nifi.web.api.dto.action.details.ActionDetailsDTO;
169 import org.apache.nifi.web.api.dto.action.details.ConfigureDetailsDTO;
170 import org.apache.nifi.web.api.dto.action.details.ConnectDetailsDTO;
171 import org.apache.nifi.web.api.dto.action.details.MoveDetailsDTO;
172 import org.apache.nifi.web.api.dto.action.details.PurgeDetailsDTO;
173 import org.apache.nifi.web.api.dto.diagnostics.ClassLoaderDiagnosticsDTO;
174 import org.apache.nifi.web.api.dto.diagnostics.ConnectionDiagnosticsDTO;
175 import org.apache.nifi.web.api.dto.diagnostics.ConnectionDiagnosticsSnapshotDTO;
176 import org.apache.nifi.web.api.dto.diagnostics.ControllerServiceDiagnosticsDTO;
177 import org.apache.nifi.web.api.dto.diagnostics.GCDiagnosticsSnapshotDTO;
178 import org.apache.nifi.web.api.dto.diagnostics.GarbageCollectionDiagnosticsDTO;
179 import org.apache.nifi.web.api.dto.diagnostics.JVMControllerDiagnosticsSnapshotDTO;
180 import org.apache.nifi.web.api.dto.diagnostics.JVMDiagnosticsDTO;
181 import org.apache.nifi.web.api.dto.diagnostics.JVMDiagnosticsSnapshotDTO;
182 import org.apache.nifi.web.api.dto.diagnostics.JVMFlowDiagnosticsSnapshotDTO;
183 import org.apache.nifi.web.api.dto.diagnostics.JVMSystemDiagnosticsSnapshotDTO;
184 import org.apache.nifi.web.api.dto.diagnostics.LocalQueuePartitionDTO;
185 import org.apache.nifi.web.api.dto.diagnostics.ProcessorDiagnosticsDTO;
186 import org.apache.nifi.web.api.dto.diagnostics.RemoteQueuePartitionDTO;
187 import org.apache.nifi.web.api.dto.diagnostics.RepositoryUsageDTO;
188 import org.apache.nifi.web.api.dto.diagnostics.ThreadDumpDTO;
189 import org.apache.nifi.web.api.dto.flow.FlowBreadcrumbDTO;
190 import org.apache.nifi.web.api.dto.flow.FlowDTO;
191 import org.apache.nifi.web.api.dto.flow.ProcessGroupFlowDTO;
192 import org.apache.nifi.web.api.dto.provenance.lineage.LineageDTO;
193 import org.apache.nifi.web.api.dto.provenance.lineage.LineageRequestDTO;
194 import org.apache.nifi.web.api.dto.provenance.lineage.LineageRequestDTO.LineageRequestType;
195 import org.apache.nifi.web.api.dto.provenance.lineage.LineageResultsDTO;
196 import org.apache.nifi.web.api.dto.provenance.lineage.ProvenanceLinkDTO;
197 import org.apache.nifi.web.api.dto.provenance.lineage.ProvenanceNodeDTO;
198 import org.apache.nifi.web.api.dto.status.ConnectionStatusDTO;
199 import org.apache.nifi.web.api.dto.status.ConnectionStatusSnapshotDTO;
200 import org.apache.nifi.web.api.dto.status.PortStatusDTO;
201 import org.apache.nifi.web.api.dto.status.PortStatusSnapshotDTO;
202 import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
203 import org.apache.nifi.web.api.dto.status.ProcessGroupStatusSnapshotDTO;
204 import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
205 import org.apache.nifi.web.api.dto.status.ProcessorStatusSnapshotDTO;
206 import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
207 import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusSnapshotDTO;
208 import org.apache.nifi.web.api.entity.AccessPolicyEntity;
209 import org.apache.nifi.web.api.entity.AccessPolicySummaryEntity;
210 import org.apache.nifi.web.api.entity.AffectedComponentEntity;
211 import org.apache.nifi.web.api.entity.AllowableValueEntity;
212 import org.apache.nifi.web.api.entity.BulletinEntity;
213 import org.apache.nifi.web.api.entity.ComponentReferenceEntity;
214 import org.apache.nifi.web.api.entity.ConnectionStatusSnapshotEntity;
215 import org.apache.nifi.web.api.entity.ControllerServiceEntity;
216 import org.apache.nifi.web.api.entity.FlowBreadcrumbEntity;
217 import org.apache.nifi.web.api.entity.PortEntity;
218 import org.apache.nifi.web.api.entity.PortStatusSnapshotEntity;
219 import org.apache.nifi.web.api.entity.ProcessGroupStatusSnapshotEntity;
220 import org.apache.nifi.web.api.entity.ProcessorEntity;
221 import org.apache.nifi.web.api.entity.ProcessorStatusSnapshotEntity;
222 import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
223 import org.apache.nifi.web.api.entity.RemoteProcessGroupStatusSnapshotEntity;
224 import org.apache.nifi.web.api.entity.TenantEntity;
225 import org.apache.nifi.web.api.entity.VariableEntity;
226 import org.apache.nifi.web.controller.ControllerFacade;
227 import org.apache.nifi.web.revision.RevisionManager;
228
229 import javax.ws.rs.WebApplicationException;
230 import java.net.UnknownHostException;
231 import java.text.Collator;
232 import java.text.NumberFormat;
233 import java.util.ArrayList;
234 import java.util.Arrays;
235 import java.util.Collection;
236 import java.util.Collections;
237 import java.util.Comparator;
238 import java.util.Date;
239 import java.util.HashMap;
240 import java.util.HashSet;
241 import java.util.Iterator;
242 import java.util.LinkedHashMap;
243 import java.util.LinkedHashSet;
244 import java.util.List;
245 import java.util.Locale;
246 import java.util.Map;
247 import java.util.Map.Entry;
248 import java.util.Set;
249 import java.util.TimeZone;
250 import java.util.TreeMap;
251 import java.util.TreeSet;
252 import java.util.concurrent.TimeUnit;
253 import java.util.function.Function;
254 import java.util.function.Supplier;
255 import java.util.stream.Collectors;
256 import java.net.InetAddress;
257
258
259 public final class DtoFactory {
260
261     @SuppressWarnings("rawtypes")
262     private final static Comparator<Class> CLASS_NAME_COMPARATOR = new Comparator<Class>() {
263         @Override
264         public int compare(final Class class1, final Class class2) {
265             return Collator.getInstance(Locale.US).compare(class1.getSimpleName(), class2.getSimpleName());
266         }
267     };
268     public static final String SENSITIVE_VALUE_MASK = "********";
269
270     private BulletinRepository bulletinRepository;
271     private ControllerServiceProvider controllerServiceProvider;
272     private EntityFactory entityFactory;
273     private Authorizer authorizer;
274     private ExtensionManager extensionManager;
275
276     public ControllerConfigurationDTO createControllerConfigurationDto(final ControllerFacade controllerFacade) {
277         final ControllerConfigurationDTO dto = new ControllerConfigurationDTO();
278         dto.setMaxTimerDrivenThreadCount(controllerFacade.getMaxTimerDrivenThreadCount());
279         dto.setMaxEventDrivenThreadCount(controllerFacade.getMaxEventDrivenThreadCount());
280         return dto;
281     }
282
283     public FlowConfigurationDTO createFlowConfigurationDto(final String autoRefreshInterval,
284                                                            final Long defaultBackPressureObjectThreshold,
285                                                            final String defaultBackPressureDataSizeThreshold) {
286         final FlowConfigurationDTO dto = new FlowConfigurationDTO();
287
288         // get the refresh interval
289         final long refreshInterval = FormatUtils.getTimeDuration(autoRefreshInterval, TimeUnit.SECONDS);
290         dto.setAutoRefreshIntervalSeconds(refreshInterval);
291         dto.setSupportsManagedAuthorizer(AuthorizerCapabilityDetection.isManagedAuthorizer(authorizer));
292         dto.setSupportsConfigurableUsersAndGroups(AuthorizerCapabilityDetection.isConfigurableUserGroupProvider(authorizer));
293         dto.setSupportsConfigurableAuthorizer(AuthorizerCapabilityDetection.isConfigurableAccessPolicyProvider(authorizer));
294
295         final Date now = new Date();
296         dto.setTimeOffset(TimeZone.getDefault().getOffset(now.getTime()));
297         dto.setCurrentTime(now);
298
299         dto.setDefaultBackPressureDataSizeThreshold(defaultBackPressureDataSizeThreshold);
300         dto.setDefaultBackPressureObjectThreshold(defaultBackPressureObjectThreshold);
301
302         return dto;
303     }
304
305     /**
306      * Creates an ActionDTO for the specified Action.
307      *
308      * @param action action
309      * @return dto
310      */
311     public ActionDTO createActionDto(final Action action) {
312         final ActionDTO actionDto = new ActionDTO();
313         actionDto.setId(action.getId());
314         actionDto.setSourceId(action.getSourceId());
315         actionDto.setSourceName(action.getSourceName());
316         actionDto.setSourceType(action.getSourceType().toString());
317         actionDto.setTimestamp(action.getTimestamp());
318         actionDto.setUserIdentity(action.getUserIdentity());
319         actionDto.setOperation(action.getOperation().toString());
320         actionDto.setActionDetails(createActionDetailsDto(action.getActionDetails()));
321         actionDto.setComponentDetails(createComponentDetailsDto(action.getComponentDetails()));
322
323         return actionDto;
324     }
325
326     /**
327      * Creates an ActionDetailsDTO for the specified ActionDetails.
328      *
329      * @param actionDetails details
330      * @return dto
331      */
332     private ActionDetailsDTO createActionDetailsDto(final ActionDetails actionDetails) {
333         if (actionDetails == null) {
334             return null;
335         }
336
337         if (actionDetails instanceof FlowChangeConfigureDetails) {
338             final ConfigureDetailsDTO configureDetails = new ConfigureDetailsDTO();
339             configureDetails.setName(((ConfigureDetails) actionDetails).getName());
340             configureDetails.setPreviousValue(((ConfigureDetails) actionDetails).getPreviousValue());
341             configureDetails.setValue(((ConfigureDetails) actionDetails).getValue());
342             return configureDetails;
343         } else if (actionDetails instanceof FlowChangeConnectDetails) {
344             final ConnectDetailsDTO connectDetails = new ConnectDetailsDTO();
345             connectDetails.setSourceId(((ConnectDetails) actionDetails).getSourceId());
346             connectDetails.setSourceName(((ConnectDetails) actionDetails).getSourceName());
347             connectDetails.setSourceType(((ConnectDetails) actionDetails).getSourceType().toString());
348             connectDetails.setRelationship(((ConnectDetails) actionDetails).getRelationship());
349             connectDetails.setDestinationId(((ConnectDetails) actionDetails).getDestinationId());
350             connectDetails.setDestinationName(((ConnectDetails) actionDetails).getDestinationName());
351             connectDetails.setDestinationType(((ConnectDetails) actionDetails).getDestinationType().toString());
352             return connectDetails;
353         } else if (actionDetails instanceof FlowChangeMoveDetails) {
354             final MoveDetailsDTO moveDetails = new MoveDetailsDTO();
355             moveDetails.setPreviousGroup(((MoveDetails) actionDetails).getPreviousGroup());
356             moveDetails.setPreviousGroupId(((MoveDetails) actionDetails).getPreviousGroupId());
357             moveDetails.setGroup(((MoveDetails) actionDetails).getGroup());
358             moveDetails.setGroupId(((MoveDetails) actionDetails).getGroupId());
359             return moveDetails;
360         } else if (actionDetails instanceof FlowChangePurgeDetails) {
361             final PurgeDetailsDTO purgeDetails = new PurgeDetailsDTO();
362             purgeDetails.setEndDate(((PurgeDetails) actionDetails).getEndDate());
363             return purgeDetails;
364         } else {
365             throw new WebApplicationException(new IllegalArgumentException(String.format("Unrecognized type of action details encountered %s during serialization.", actionDetails.toString())));
366         }
367     }
368
369     /**
370      * Creates a ComponentDetailsDTO for the specified ComponentDetails.
371      *
372      * @param componentDetails details
373      * @return dto
374      */
375     private ComponentDetailsDTO createComponentDetailsDto(final ComponentDetails componentDetails) {
376         if (componentDetails == null) {
377             return null;
378         }
379
380         if (componentDetails instanceof FlowChangeExtensionDetails) {
381             final ExtensionDetailsDTO processorDetails = new ExtensionDetailsDTO();
382             processorDetails.setType(((ExtensionDetails) componentDetails).getType());
383             return processorDetails;
384         } else if (componentDetails instanceof FlowChangeRemoteProcessGroupDetails) {
385             final RemoteProcessGroupDetailsDTO remoteProcessGroupDetails = new RemoteProcessGroupDetailsDTO();
386             remoteProcessGroupDetails.setUri(((RemoteProcessGroupDetails) componentDetails).getUri());
387             return remoteProcessGroupDetails;
388         } else {
389             throw new WebApplicationException(new IllegalArgumentException(String.format("Unrecognized type of component details encountered %s during serialization. ", componentDetails.toString())));
390         }
391     }
392
393     /**
394      * Creates a HistoryDTO from the specified History.
395      *
396      * @param history history
397      * @return dto
398      */
399     public HistoryDTO createHistoryDto(final History history) {
400         final HistoryDTO historyDto = new HistoryDTO();
401         historyDto.setTotal(history.getTotal());
402         historyDto.setLastRefreshed(history.getLastRefreshed());
403         return historyDto;
404     }
405
406     /**
407      * Creates a ComponentStateDTO for the given component and state's.
408      *
409      * @param componentId component id
410      * @param localState local state
411      * @param clusterState cluster state
412      * @return dto
413      */
414     public ComponentStateDTO createComponentStateDTO(final String componentId, final Class<?> componentClass, final StateMap localState, final StateMap clusterState) {
415         final ComponentStateDTO dto = new ComponentStateDTO();
416         dto.setComponentId(componentId);
417         dto.setStateDescription(getStateDescription(componentClass));
418         dto.setLocalState(createStateMapDTO(Scope.LOCAL, localState));
419         dto.setClusterState(createStateMapDTO(Scope.CLUSTER, clusterState));
420         return dto;
421     }
422
423     /**
424      * Gets the description of the state this component persists.
425      *
426      * @param componentClass the component class
427      * @return state description
428      */
429     private String getStateDescription(final Class<?> componentClass) {
430         final Stateful capabilityDesc = componentClass.getAnnotation(Stateful.class);
431         if (capabilityDesc != null) {
432             return capabilityDesc.description();
433         } else {
434             return null;
435         }
436     }
437
438     /**
439      * Creates a StateMapDTO for the given scope and state map.
440      *
441      * @param scope the scope
442      * @param stateMap the state map
443      * @return dto
444      */
445     public StateMapDTO createStateMapDTO(final Scope scope, final StateMap stateMap) {
446         if (stateMap == null) {
447             return null;
448         }
449
450         final StateMapDTO dto = new StateMapDTO();
451         dto.setScope(scope.toString());
452
453         final TreeMap<String, String> sortedState = new TreeMap<>(SortedStateUtils.getKeyComparator());
454         final Map<String, String> state = stateMap.toMap();
455         sortedState.putAll(state);
456
457         int count = 0;
458         final List<StateEntryDTO> stateEntries = new ArrayList<>();
459         final Set<Map.Entry<String, String>> entrySet = sortedState.entrySet();
460         for (final Iterator<Entry<String, String>> iter = entrySet.iterator(); iter.hasNext() && count++ < SortedStateUtils.MAX_COMPONENT_STATE_ENTRIES;) {
461             final Map.Entry<String, String> entry = iter.next();
462             final StateEntryDTO entryDTO = new StateEntryDTO();
463             entryDTO.setKey(entry.getKey());
464             entryDTO.setValue(entry.getValue());
465             stateEntries.add(entryDTO);
466         }
467         dto.setTotalEntryCount(state.size());
468         dto.setState(stateEntries);
469
470         return dto;
471     }
472
473     /**
474      * Creates CounterDTOs for each Counter specified.
475      *
476      * @param counterDtos dtos
477      * @return dto
478      */
479     public CountersSnapshotDTO createCountersDto(final Collection<CounterDTO> counterDtos) {
480         final CountersSnapshotDTO dto = new CountersSnapshotDTO();
481         dto.setCounters(counterDtos);
482         dto.setGenerated(new Date());
483         return dto;
484     }
485
486     /**
487      * Creates a CounterDTO from the specified Counter.
488      *
489      * @param counter counter
490      * @return dto
491      */
492     public CounterDTO createCounterDto(final Counter counter) {
493         final CounterDTO dto = new CounterDTO();
494         dto.setId(counter.getIdentifier());
495         dto.setContext(counter.getContext());
496         dto.setName(counter.getName());
497         dto.setValueCount(counter.getValue());
498         dto.setValue(FormatUtils.formatCount(counter.getValue()));
499         return dto;
500     }
501
502     /**
503      * Creates a PositionDTO from the specified position
504      *
505      * @param position position
506      * @return dto
507      */
508     public PositionDTO createPositionDto(final Position position) {
509         return new PositionDTO(position.getX(), position.getY());
510     }
511
512     private boolean isDropRequestComplete(final DropFlowFileState state) {
513         return DropFlowFileState.COMPLETE.equals(state) || DropFlowFileState.CANCELED.equals(state) || DropFlowFileState.FAILURE.equals(state);
514     }
515
516     /**
517      * Creates a DropRequestDTO from the specified flow file status.
518      *
519      * @param dropRequest dropRequest
520      * @return dto
521      */
522     public DropRequestDTO createDropRequestDTO(final DropFlowFileStatus dropRequest) {
523         final DropRequestDTO dto = new DropRequestDTO();
524         dto.setId(dropRequest.getRequestIdentifier());
525         dto.setSubmissionTime(new Date(dropRequest.getRequestSubmissionTime()));
526         dto.setLastUpdated(new Date(dropRequest.getLastUpdated()));
527         dto.setState(dropRequest.getState().toString());
528         dto.setFailureReason(dropRequest.getFailureReason());
529         dto.setFinished(isDropRequestComplete(dropRequest.getState()));
530
531         final QueueSize dropped = dropRequest.getDroppedSize();
532         dto.setDroppedCount(dropped.getObjectCount());
533         dto.setDroppedSize(dropped.getByteCount());
534         dto.setDropped(FormatUtils.formatCount(dropped.getObjectCount()) + " / " + FormatUtils.formatDataSize(dropped.getByteCount()));
535
536         final QueueSize current = dropRequest.getCurrentSize();
537         dto.setCurrentCount(current.getObjectCount());
538         dto.setCurrentSize(current.getByteCount());
539         dto.setCurrent(FormatUtils.formatCount(current.getObjectCount()) + " / " + FormatUtils.formatDataSize(current.getByteCount()));
540
541         final QueueSize original = dropRequest.getOriginalSize();
542         dto.setOriginalCount(original.getObjectCount());
543         dto.setOriginalSize(original.getByteCount());
544         dto.setOriginal(FormatUtils.formatCount(original.getObjectCount()) + " / " + FormatUtils.formatDataSize(original.getByteCount()));
545
546         if (isDropRequestComplete(dropRequest.getState())) {
547             dto.setPercentCompleted(100);
548         } else {
549             dto.setPercentCompleted((dropped.getObjectCount() * 100) / original.getObjectCount());
550         }
551
552         return dto;
553     }
554
555     private boolean isListingRequestComplete(final ListFlowFileState state) {
556         return ListFlowFileState.COMPLETE.equals(state) || ListFlowFileState.CANCELED.equals(state) || ListFlowFileState.FAILURE.equals(state);
557     }
558
559     private QueueSizeDTO createQueueSizeDTO(final QueueSize queueSize) {
560         final QueueSizeDTO dto = new QueueSizeDTO();
561         dto.setByteCount(queueSize.getByteCount());
562         dto.setObjectCount(queueSize.getObjectCount());
563         return dto;
564     }
565
566     /**
567      * Creates a ListingRequestDTO from the specified ListFlowFileStatus.
568      *
569      * @param listingRequest listingRequest
570      * @return dto
571      */
572     public ListingRequestDTO createListingRequestDTO(final ListFlowFileStatus listingRequest) {
573         final ListingRequestDTO dto = new ListingRequestDTO();
574         dto.setId(listingRequest.getRequestIdentifier());
575         dto.setSubmissionTime(new Date(listingRequest.getRequestSubmissionTime()));
576         dto.setLastUpdated(new Date(listingRequest.getLastUpdated()));
577         dto.setState(listingRequest.getState().toString());
578         dto.setFailureReason(listingRequest.getFailureReason());
579         dto.setFinished(isListingRequestComplete(listingRequest.getState()));
580         dto.setMaxResults(listingRequest.getMaxResults());
581         dto.setPercentCompleted(listingRequest.getCompletionPercentage());
582
583         dto.setQueueSize(createQueueSizeDTO(listingRequest.getQueueSize()));
584
585         if (isListingRequestComplete(listingRequest.getState())) {
586             final List<FlowFileSummary> flowFileSummaries = listingRequest.getFlowFileSummaries();
587             if (flowFileSummaries != null) {
588                 final Date now = new Date();
589                 final List<FlowFileSummaryDTO> summaryDtos = new ArrayList<>(flowFileSummaries.size());
590                 for (final FlowFileSummary summary : flowFileSummaries) {
591                     summaryDtos.add(createFlowFileSummaryDTO(summary, now));
592                 }
593                 dto.setFlowFileSummaries(summaryDtos);
594             }
595         }
596
597         return dto;
598     }
599
600     /**
601      * Creates a FlowFileSummaryDTO from the specified FlowFileSummary.
602      *
603      * @param summary summary
604      * @return dto
605      */
606     public FlowFileSummaryDTO createFlowFileSummaryDTO(final FlowFileSummary summary, final Date now) {
607         final FlowFileSummaryDTO dto = new FlowFileSummaryDTO();
608         dto.setUuid(summary.getUuid());
609         dto.setFilename(summary.getFilename());
610
611         dto.setPenalized(summary.isPenalized());
612         final long penaltyExpiration = summary.getPenaltyExpirationMillis() - now.getTime();
613         dto.setPenaltyExpiresIn(penaltyExpiration>=0?penaltyExpiration:0);
614
615         dto.setPosition(summary.getPosition());
616         dto.setSize(summary.getSize());
617
618         final long queuedDuration = now.getTime() - summary.getLastQueuedTime();
619         dto.setQueuedDuration(queuedDuration);
620
621         final long age = now.getTime() - summary.getLineageStartDate();
622         dto.setLineageDuration(age);
623
624         return dto;
625     }
626
627     /**
628      * Creates a FlowFileDTO from the specified FlowFileRecord.
629      *
630      * @param record record
631      * @return dto
632      */
633     public FlowFileDTO createFlowFileDTO(final FlowFileRecord record) {
634         final Date now = new Date();
635         final FlowFileDTO dto = new FlowFileDTO();
636         dto.setUuid(record.getAttribute(CoreAttributes.UUID.key()));
637         dto.setFilename(record.getAttribute(CoreAttributes.FILENAME.key()));
638
639         dto.setPenalized(record.isPenalized());
640         final long penaltyExpiration = record.getPenaltyExpirationMillis() - now.getTime();
641         dto.setPenaltyExpiresIn(penaltyExpiration>=0?penaltyExpiration:0);
642
643         dto.setSize(record.getSize());
644         dto.setAttributes(record.getAttributes());
645
646         final long queuedDuration = now.getTime() - record.getLastQueueDate();
647         dto.setQueuedDuration(queuedDuration);
648
649         final long age = now.getTime() - record.getLineageStartDate();
650         dto.setLineageDuration(age);
651
652         final ContentClaim contentClaim = record.getContentClaim();
653         if (contentClaim != null) {
654             final ResourceClaim resourceClaim = contentClaim.getResourceClaim();
655             dto.setContentClaimSection(resourceClaim.getSection());
656             dto.setContentClaimContainer(resourceClaim.getContainer());
657             dto.setContentClaimIdentifier(resourceClaim.getId());
658             dto.setContentClaimOffset(contentClaim.getOffset() + record.getContentClaimOffset());
659             dto.setContentClaimFileSizeBytes(record.getSize());
660             dto.setContentClaimFileSize(FormatUtils.formatDataSize(record.getSize()));
661         }
662
663         return dto;
664     }
665
666     /**
667      * Creates a ConnectionDTO from the specified Connection.
668      *
669      * @param connection connection
670      * @return dto
671      */
672     public ConnectionDTO createConnectionDto(final Connection connection) {
673         if (connection == null) {
674             return null;
675         }
676
677         final ConnectionDTO dto = new ConnectionDTO();
678
679         dto.setId(connection.getIdentifier());
680         dto.setParentGroupId(connection.getProcessGroup().getIdentifier());
681
682         final List<PositionDTO> bendPoints = new ArrayList<>();
683         for (final Position bendPoint : connection.getBendPoints()) {
684             bendPoints.add(createPositionDto(bendPoint));
685         }
686         dto.setBends(bendPoints);
687         dto.setName(connection.getName());
688         dto.setLabelIndex(connection.getLabelIndex());
689         dto.setzIndex(connection.getZIndex());
690         dto.setSource(createConnectableDto(connection.getSource()));
691         dto.setDestination(createConnectableDto(connection.getDestination()));
692         dto.setVersionedComponentId(connection.getVersionedComponentId().orElse(null));
693
694         final FlowFileQueue flowFileQueue = connection.getFlowFileQueue();
695
696         dto.setBackPressureObjectThreshold(flowFileQueue.getBackPressureObjectThreshold());
697         dto.setBackPressureDataSizeThreshold(flowFileQueue.getBackPressureDataSizeThreshold());
698         dto.setFlowFileExpiration(flowFileQueue.getFlowFileExpiration());
699         dto.setPrioritizers(new ArrayList<String>());
700         for (final FlowFilePrioritizer comparator : flowFileQueue.getPriorities()) {
701             dto.getPrioritizers().add(comparator.getClass().getCanonicalName());
702         }
703
704         // For ports, we do not want to populate the relationships.
705         for (final Relationship selectedRelationship : connection.getRelationships()) {
706             if (!Relationship.ANONYMOUS.equals(selectedRelationship)) {
707                 if (dto.getSelectedRelationships() == null) {
708                     dto.setSelectedRelationships(new TreeSet<String>(Collator.getInstance(Locale.US)));
709                 }
710
711                 dto.getSelectedRelationships().add(selectedRelationship.getName());
712             }
713         }
714
715         // For ports, we do not want to populate the relationships.
716         for (final Relationship availableRelationship : connection.getSource().getRelationships()) {
717             if (!Relationship.ANONYMOUS.equals(availableRelationship)) {
718                 if (dto.getAvailableRelationships() == null) {
719                     dto.setAvailableRelationships(new TreeSet<String>(Collator.getInstance(Locale.US)));
720                 }
721
722                 dto.getAvailableRelationships().add(availableRelationship.getName());
723             }
724         }
725
726         final LoadBalanceStrategy loadBalanceStrategy = flowFileQueue.getLoadBalanceStrategy();
727         dto.setLoadBalancePartitionAttribute(flowFileQueue.getPartitioningAttribute());
728         dto.setLoadBalanceStrategy(loadBalanceStrategy.name());
729         dto.setLoadBalanceCompression(flowFileQueue.getLoadBalanceCompression().name());
730
731         if (loadBalanceStrategy == LoadBalanceStrategy.DO_NOT_LOAD_BALANCE) {
732             dto.setLoadBalanceStatus(ConnectionDTO.LOAD_BALANCE_NOT_CONFIGURED);
733         } else if (flowFileQueue.isActivelyLoadBalancing()) {
734             dto.setLoadBalanceStatus(ConnectionDTO.LOAD_BALANCE_ACTIVE);
735         } else {
736             dto.setLoadBalanceStatus(ConnectionDTO.LOAD_BALANCE_INACTIVE);
737         }
738
739         return dto;
740     }
741
742     /**
743      * Creates a ConnectableDTO from the specified Connectable.
744      *
745      * @param connectable connectable
746      * @return dto
747      */
748     public ConnectableDTO createConnectableDto(final Connectable connectable) {
749         if (connectable == null) {
750             return null;
751         }
752
753         boolean isAuthorized = connectable.isAuthorized(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
754
755         final ConnectableDTO dto = new ConnectableDTO();
756         dto.setId(connectable.getIdentifier());
757         dto.setName(isAuthorized ? connectable.getName() : connectable.getIdentifier());
758         dto.setType(connectable.getConnectableType().name());
759         dto.setVersionedComponentId(connectable.getVersionedComponentId().orElse(null));
760
761         if (connectable instanceof RemoteGroupPort) {
762             final RemoteGroupPort remoteGroupPort = (RemoteGroupPort) connectable;
763             final RemoteProcessGroup remoteGroup = remoteGroupPort.getRemoteProcessGroup();
764             dto.setGroupId(remoteGroup.getIdentifier());
765             dto.setRunning(remoteGroupPort.isTargetRunning());
766             dto.setTransmitting(remoteGroupPort.isRunning());
767             dto.setExists(remoteGroupPort.getTargetExists());
768             if (isAuthorized) {
769                 dto.setComments(remoteGroup.getComments());
770             }
771         } else {
772             dto.setGroupId(connectable.getProcessGroup().getIdentifier());
773             dto.setRunning(connectable.isRunning());
774             if (isAuthorized) {
775                 dto.setComments(connectable.getComments());
776             }
777         }
778
779         return dto;
780     }
781
782     /**
783      * Creates a LabelDTO from the specified Label.
784      *
785      * @param label label
786      * @return dto
787      */
788     public LabelDTO createLabelDto(final Label label) {
789         if (label == null) {
790             return null;
791         }
792
793         final LabelDTO dto = new LabelDTO();
794         dto.setId(label.getIdentifier());
795         dto.setPosition(createPositionDto(label.getPosition()));
796         dto.setStyle(label.getStyle());
797         dto.setHeight(label.getSize().getHeight());
798         dto.setWidth(label.getSize().getWidth());
799         dto.setLabel(label.getValue());
800         dto.setParentGroupId(label.getProcessGroup().getIdentifier());
801         dto.setVersionedComponentId(label.getVersionedComponentId().orElse(null));
802
803         return dto;
804     }
805
806     /**
807      * Creates a {@link UserDTO} from the specified {@link User}.
808      *
809      * @param user user
810      * @return dto
811      */
812     public UserDTO createUserDto(final User user, final Set<TenantEntity> groups, final Set<AccessPolicySummaryEntity> accessPolicies) {
813         if (user == null) {
814             return null;
815         }
816
817         final UserDTO dto = new UserDTO();
818         dto.setId(user.getIdentifier());
819         dto.setUserGroups(groups);
820         dto.setIdentity(user.getIdentity());
821         dto.setConfigurable(AuthorizerCapabilityDetection.isUserConfigurable(authorizer, user));
822         dto.setAccessPolicies(accessPolicies);
823
824         return dto;
825     }
826
827     /**
828      * Creates a {@link TenantDTO} from the specified {@link User}.
829      *
830      * @param user user
831      * @return dto
832      */
833     public TenantDTO createTenantDTO(User user) {
834         if (user == null) {
835             return null;
836         }
837
838         final TenantDTO dto = new TenantDTO();
839         dto.setId(user.getIdentifier());
840         dto.setIdentity(user.getIdentity());
841         dto.setConfigurable(AuthorizerCapabilityDetection.isUserConfigurable(authorizer, user));
842
843         return dto;
844     }
845
846     /**
847      * Creates a {@link UserGroupDTO} from the specified {@link Group}.
848      *
849      * @param userGroup user group
850      * @return dto
851      */
852     public UserGroupDTO createUserGroupDto(final Group userGroup, Set<TenantEntity> users, final Set<AccessPolicySummaryEntity> accessPolicies) {
853         if (userGroup == null) {
854             return null;
855         }
856
857         // convert to access policies to handle backward compatibility due to incorrect
858         // type in the UserGroupDTO
859         final Set<AccessPolicyEntity> policies = accessPolicies.stream().map(summaryEntity -> {
860             final AccessPolicyDTO policy = new AccessPolicyDTO();
861             policy.setId(summaryEntity.getId());
862
863             if (summaryEntity.getPermissions().getCanRead()) {
864                 final AccessPolicySummaryDTO summary = summaryEntity.getComponent();
865                 policy.setResource(summary.getResource());
866                 policy.setAction(summary.getAction());
867                 policy.setConfigurable(summary.getConfigurable());
868                 policy.setComponentReference(summary.getComponentReference());
869             }
870
871             return entityFactory.createAccessPolicyEntity(policy, summaryEntity.getRevision(), summaryEntity.getPermissions());
872         }).collect(Collectors.toSet());
873
874         final UserGroupDTO dto = new UserGroupDTO();
875         dto.setId(userGroup.getIdentifier());
876         dto.setUsers(users);
877         dto.setIdentity(userGroup.getName());
878         dto.setConfigurable(AuthorizerCapabilityDetection.isGroupConfigurable(authorizer, userGroup));
879         dto.setAccessPolicies(policies);
880
881         return dto;
882     }
883
884     /**
885      * Creates a {@link TenantDTO} from the specified {@link User}.
886      *
887      * @param userGroup user
888      * @return dto
889      */
890     public TenantDTO createTenantDTO(Group userGroup) {
891         if (userGroup == null) {
892             return null;
893         }
894
895         final TenantDTO dto = new TenantDTO();
896         dto.setId(userGroup.getIdentifier());
897         dto.setIdentity(userGroup.getName());
898         dto.setConfigurable(AuthorizerCapabilityDetection.isGroupConfigurable(authorizer, userGroup));
899
900         return dto;
901     }
902
903     /**
904      * Creates a FunnelDTO from the specified Funnel.
905      *
906      * @param funnel funnel
907      * @return dto
908      */
909     public FunnelDTO createFunnelDto(final Funnel funnel) {
910         if (funnel == null) {
911             return null;
912         }
913
914         final FunnelDTO dto = new FunnelDTO();
915         dto.setId(funnel.getIdentifier());
916         dto.setPosition(createPositionDto(funnel.getPosition()));
917         dto.setParentGroupId(funnel.getProcessGroup().getIdentifier());
918         dto.setVersionedComponentId(funnel.getVersionedComponentId().orElse(null));
919
920         return dto;
921     }
922
923     /**
924      * Creates a SnippetDTO from the specified Snippet.
925      *
926      * @param snippet snippet
927      * @return dto
928      */
929     public SnippetDTO createSnippetDto(final Snippet snippet) {
930         final SnippetDTO dto = new SnippetDTO();
931         dto.setId(snippet.getId());
932         dto.setParentGroupId(snippet.getParentGroupId());
933
934         // populate the snippet contents ids
935         dto.setConnections(mapRevisionToDto(snippet.getConnections()));
936         dto.setFunnels(mapRevisionToDto(snippet.getFunnels()));
937         dto.setInputPorts(mapRevisionToDto(snippet.getInputPorts()));
938         dto.setLabels(mapRevisionToDto(snippet.getLabels()));
939         dto.setOutputPorts(mapRevisionToDto(snippet.getOutputPorts()));
940         dto.setProcessGroups(mapRevisionToDto(snippet.getProcessGroups()));
941         dto.setProcessors(mapRevisionToDto(snippet.getProcessors()));
942         dto.setRemoteProcessGroups(mapRevisionToDto(snippet.getRemoteProcessGroups()));
943
944         return dto;
945     }
946
947     private Map<String, RevisionDTO> mapRevisionToDto(final Map<String, Revision> revisionMap) {
948         final Map<String, RevisionDTO> dtos = new HashMap<>(revisionMap.size());
949         for (final Map.Entry<String, Revision> entry : revisionMap.entrySet()) {
950             final Revision revision = entry.getValue();
951             final RevisionDTO revisionDto = new RevisionDTO();
952             revisionDto.setClientId(revision.getClientId());
953             revisionDto.setVersion(revision.getVersion());
954
955             dtos.put(entry.getKey(), revisionDto);
956         }
957         return dtos;
958     }
959
960     /**
961      * Creates a TemplateDTO from the specified template.
962      *
963      * @param template template
964      * @return dto
965      */
966     public TemplateDTO createTemplateDTO(final Template template) {
967         if (template == null) {
968             return null;
969         }
970
971         final TemplateDTO original = template.getDetails();
972
973         final TemplateDTO copy = new TemplateDTO();
974         copy.setId(original.getId());
975         copy.setGroupId(template.getProcessGroup().getIdentifier());
976         copy.setName(original.getName());
977         copy.setDescription(original.getDescription());
978         copy.setTimestamp(original.getTimestamp());
979         copy.setUri(original.getUri());
980         copy.setEncodingVersion(original.getEncodingVersion());
981
982         return copy;
983     }
984
985
986     public RemoteProcessGroupStatusDTO createRemoteProcessGroupStatusDto(final RemoteProcessGroup remoteProcessGroup, final RemoteProcessGroupStatus remoteProcessGroupStatus) {
987         final RemoteProcessGroupStatusDTO dto = new RemoteProcessGroupStatusDTO();
988         dto.setId(remoteProcessGroupStatus.getId());
989         dto.setGroupId(remoteProcessGroupStatus.getGroupId());
990         dto.setTargetUri(remoteProcessGroupStatus.getTargetUri());
991         dto.setName(remoteProcessGroupStatus.getName());
992         dto.setTransmissionStatus(remoteProcessGroupStatus.getTransmissionStatus().toString());
993         dto.setStatsLastRefreshed(new Date());
994         dto.setValidationStatus(getRemoteProcessGroupValidationStatus(remoteProcessGroup).name());
995
996         final RemoteProcessGroupStatusSnapshotDTO snapshot = new RemoteProcessGroupStatusSnapshotDTO();
997         dto.setAggregateSnapshot(snapshot);
998
999         snapshot.setId(remoteProcessGroupStatus.getId());
1000         snapshot.setGroupId(remoteProcessGroupStatus.getGroupId());
1001         snapshot.setName(remoteProcessGroupStatus.getName());
1002         snapshot.setTargetUri(remoteProcessGroupStatus.getTargetUri());
1003         snapshot.setTransmissionStatus(remoteProcessGroupStatus.getTransmissionStatus().toString());
1004
1005         snapshot.setActiveThreadCount(remoteProcessGroupStatus.getActiveThreadCount());
1006         snapshot.setFlowFilesSent(remoteProcessGroupStatus.getSentCount());
1007         snapshot.setBytesSent(remoteProcessGroupStatus.getSentContentSize());
1008         snapshot.setFlowFilesReceived(remoteProcessGroupStatus.getReceivedCount());
1009         snapshot.setBytesReceived(remoteProcessGroupStatus.getReceivedContentSize());
1010
1011         StatusMerger.updatePrettyPrintedFields(snapshot);
1012         return dto;
1013     }
1014
1015     private ValidationStatus getRemoteProcessGroupValidationStatus(RemoteProcessGroup remoteProcessGroup) {
1016         final boolean hasAuthIssue = remoteProcessGroup.getAuthorizationIssue() != null && !remoteProcessGroup.getAuthorizationIssue().isEmpty();
1017         final Collection<ValidationResult> validationResults = remoteProcessGroup.validate();
1018         final boolean hasValidationIssue = validationResults != null && !validationResults.isEmpty();
1019         return hasAuthIssue || hasValidationIssue ? ValidationStatus.INVALID : ValidationStatus.VALID;
1020     }
1021
1022     public ProcessGroupStatusDTO createConciseProcessGroupStatusDto(final ProcessGroupStatus processGroupStatus) {
1023         final ProcessGroupStatusDTO processGroupStatusDto = new ProcessGroupStatusDTO();
1024         processGroupStatusDto.setId(processGroupStatus.getId());
1025         processGroupStatusDto.setName(processGroupStatus.getName());
1026         processGroupStatusDto.setStatsLastRefreshed(new Date());
1027
1028         final ProcessGroupStatusSnapshotDTO snapshot = new ProcessGroupStatusSnapshotDTO();
1029         processGroupStatusDto.setAggregateSnapshot(snapshot);
1030
1031         snapshot.setId(processGroupStatus.getId());
1032         snapshot.setName(processGroupStatus.getName());
1033
1034         if (processGroupStatus.getVersionedFlowState() != null) {
1035             snapshot.setVersionedFlowState(processGroupStatus.getVersionedFlowState().name());
1036         }
1037
1038         snapshot.setFlowFilesQueued(processGroupStatus.getQueuedCount());
1039         snapshot.setBytesQueued(processGroupStatus.getQueuedContentSize());
1040         snapshot.setBytesRead(processGroupStatus.getBytesRead());
1041         snapshot.setBytesWritten(processGroupStatus.getBytesWritten());
1042         snapshot.setFlowFilesIn(processGroupStatus.getInputCount());
1043         snapshot.setBytesIn(processGroupStatus.getInputContentSize());
1044         snapshot.setFlowFilesOut(processGroupStatus.getOutputCount());
1045         snapshot.setBytesOut(processGroupStatus.getOutputContentSize());
1046         snapshot.setFlowFilesTransferred(processGroupStatus.getFlowFilesTransferred());
1047         snapshot.setBytesTransferred(processGroupStatus.getBytesTransferred());
1048         snapshot.setFlowFilesSent(processGroupStatus.getFlowFilesSent());
1049         snapshot.setBytesSent(processGroupStatus.getBytesSent());
1050         snapshot.setFlowFilesReceived(processGroupStatus.getFlowFilesReceived());
1051         snapshot.setBytesReceived(processGroupStatus.getBytesReceived());
1052
1053         snapshot.setActiveThreadCount(processGroupStatus.getActiveThreadCount());
1054         snapshot.setTerminatedThreadCount(processGroupStatus.getTerminatedThreadCount());
1055
1056         StatusMerger.updatePrettyPrintedFields(snapshot);
1057         return processGroupStatusDto;
1058     }
1059
1060     public ProcessGroupStatusDTO createProcessGroupStatusDto(final ProcessGroup processGroup, final ProcessGroupStatus processGroupStatus) {
1061         final ProcessGroupStatusDTO processGroupStatusDto = createConciseProcessGroupStatusDto(processGroupStatus);
1062         final ProcessGroupStatusSnapshotDTO snapshot = processGroupStatusDto.getAggregateSnapshot();
1063
1064         // processor status
1065         final Collection<ProcessorStatusSnapshotEntity> processorStatusSnapshotEntities = new ArrayList<>();
1066         snapshot.setProcessorStatusSnapshots(processorStatusSnapshotEntities);
1067         final Collection<ProcessorStatus> processorStatusCollection = processGroupStatus.getProcessorStatus();
1068         if (processorStatusCollection != null) {
1069             for (final ProcessorStatus processorStatus : processorStatusCollection) {
1070                 final ProcessorStatusDTO processorStatusDto = createProcessorStatusDto(processorStatus);
1071                 final ProcessorNode processor = processGroup.findProcessor(processorStatusDto.getId());
1072                 final PermissionsDTO processorPermissions = createPermissionsDto(processor);
1073                 processorStatusSnapshotEntities.add(entityFactory.createProcessorStatusSnapshotEntity(processorStatusDto.getAggregateSnapshot(), processorPermissions));
1074             }
1075         }
1076
1077         // connection status
1078         final Collection<ConnectionStatusSnapshotEntity> connectionStatusDtoCollection = new ArrayList<>();
1079         snapshot.setConnectionStatusSnapshots(connectionStatusDtoCollection);
1080         final Collection<ConnectionStatus> connectionStatusCollection = processGroupStatus.getConnectionStatus();
1081         if (connectionStatusCollection != null) {
1082             for (final ConnectionStatus connectionStatus : connectionStatusCollection) {
1083                 final ConnectionStatusDTO connectionStatusDto = createConnectionStatusDto(connectionStatus);
1084                 final Connection connection = processGroup.findConnection(connectionStatusDto.getId());
1085                 final PermissionsDTO connectionPermissions = createPermissionsDto(connection);
1086                 connectionStatusDtoCollection.add(entityFactory.createConnectionStatusSnapshotEntity(connectionStatusDto.getAggregateSnapshot(), connectionPermissions));
1087             }
1088         }
1089
1090         // local child process groups
1091         final Collection<ProcessGroupStatusSnapshotEntity> childProcessGroupStatusDtoCollection = new ArrayList<>();
1092         snapshot.setProcessGroupStatusSnapshots(childProcessGroupStatusDtoCollection);
1093         final Collection<ProcessGroupStatus> childProcessGroupStatusCollection = processGroupStatus.getProcessGroupStatus();
1094         if (childProcessGroupStatusCollection != null) {
1095             for (final ProcessGroupStatus childProcessGroupStatus : childProcessGroupStatusCollection) {
1096                 final ProcessGroupStatusDTO childProcessGroupStatusDto = createProcessGroupStatusDto(processGroup, childProcessGroupStatus);
1097                 final ProcessGroup childProcessGroup = processGroup.findProcessGroup(childProcessGroupStatusDto.getId());
1098                 final PermissionsDTO childProcessGroupPermissions = createPermissionsDto(childProcessGroup);
1099                 childProcessGroupStatusDtoCollection.add(entityFactory.createProcessGroupStatusSnapshotEntity(childProcessGroupStatusDto.getAggregateSnapshot(), childProcessGroupPermissions));
1100             }
1101         }
1102
1103         // remote child process groups
1104         final Collection<RemoteProcessGroupStatusSnapshotEntity> childRemoteProcessGroupStatusDtoCollection = new ArrayList<>();
1105         snapshot.setRemoteProcessGroupStatusSnapshots(childRemoteProcessGroupStatusDtoCollection);
1106         final Collection<RemoteProcessGroupStatus> childRemoteProcessGroupStatusCollection = processGroupStatus.getRemoteProcessGroupStatus();
1107         if (childRemoteProcessGroupStatusCollection != null) {
1108             for (final RemoteProcessGroupStatus childRemoteProcessGroupStatus : childRemoteProcessGroupStatusCollection) {
1109                 final RemoteProcessGroup remoteProcessGroup = processGroup.findRemoteProcessGroup(childRemoteProcessGroupStatus.getId());
1110                 final RemoteProcessGroupStatusDTO childRemoteProcessGroupStatusDto = createRemoteProcessGroupStatusDto(remoteProcessGroup, childRemoteProcessGroupStatus);
1111                 final PermissionsDTO remoteProcessGroupPermissions = createPermissionsDto(remoteProcessGroup);
1112                 childRemoteProcessGroupStatusDtoCollection.add(entityFactory.createRemoteProcessGroupStatusSnapshotEntity(childRemoteProcessGroupStatusDto.getAggregateSnapshot(),
1113                         remoteProcessGroupPermissions));
1114             }
1115         }
1116
1117         // input ports
1118         final Collection<PortStatusSnapshotEntity> inputPortStatusDtoCollection = new ArrayList<>();
1119         snapshot.setInputPortStatusSnapshots(inputPortStatusDtoCollection);
1120         final Collection<PortStatus> inputPortStatusCollection = processGroupStatus.getInputPortStatus();
1121         if (inputPortStatusCollection != null) {
1122             for (final PortStatus portStatus : inputPortStatusCollection) {
1123                 final PortStatusDTO portStatusDto = createPortStatusDto(portStatus);
1124                 final Port inputPort = processGroup.findInputPort(portStatus.getId());
1125                 final PermissionsDTO inputPortPermissions = createPermissionsDto(inputPort);
1126                 inputPortStatusDtoCollection.add(entityFactory.createPortStatusSnapshotEntity(portStatusDto.getAggregateSnapshot(), inputPortPermissions));
1127             }
1128         }
1129
1130         // output ports
1131         final Collection<PortStatusSnapshotEntity> outputPortStatusDtoCollection = new ArrayList<>();
1132         snapshot.setOutputPortStatusSnapshots(outputPortStatusDtoCollection);
1133         final Collection<PortStatus> outputPortStatusCollection = processGroupStatus.getOutputPortStatus();
1134         if (outputPortStatusCollection != null) {
1135             for (final PortStatus portStatus : outputPortStatusCollection) {
1136                 final PortStatusDTO portStatusDto = createPortStatusDto(portStatus);
1137                 final Port outputPort = processGroup.findOutputPort(portStatus.getId());
1138                 final PermissionsDTO outputPortPermissions = createPermissionsDto(outputPort);
1139                 outputPortStatusDtoCollection.add(entityFactory.createPortStatusSnapshotEntity(portStatusDto.getAggregateSnapshot(), outputPortPermissions));
1140             }
1141         }
1142
1143         return processGroupStatusDto;
1144     }
1145
1146     public ConnectionStatusDTO createConnectionStatusDto(final ConnectionStatus connectionStatus) {
1147         final ConnectionStatusDTO connectionStatusDto = new ConnectionStatusDTO();
1148         connectionStatusDto.setGroupId(connectionStatus.getGroupId());
1149         connectionStatusDto.setId(connectionStatus.getId());
1150         connectionStatusDto.setName(connectionStatus.getName());
1151         connectionStatusDto.setSourceId(connectionStatus.getSourceId());
1152         connectionStatusDto.setSourceName(connectionStatus.getSourceName());
1153         connectionStatusDto.setDestinationId(connectionStatus.getDestinationId());
1154         connectionStatusDto.setDestinationName(connectionStatus.getDestinationName());
1155         connectionStatusDto.setStatsLastRefreshed(new Date());
1156
1157         final ConnectionStatusSnapshotDTO snapshot = new ConnectionStatusSnapshotDTO();
1158         connectionStatusDto.setAggregateSnapshot(snapshot);
1159
1160         snapshot.setId(connectionStatus.getId());
1161         snapshot.setGroupId(connectionStatus.getGroupId());
1162         snapshot.setName(connectionStatus.getName());
1163         snapshot.setSourceName(connectionStatus.getSourceName());
1164         snapshot.setDestinationName(connectionStatus.getDestinationName());
1165
1166         snapshot.setFlowFilesQueued(connectionStatus.getQueuedCount());
1167         snapshot.setBytesQueued(connectionStatus.getQueuedBytes());
1168
1169         snapshot.setFlowFilesIn(connectionStatus.getInputCount());
1170         snapshot.setBytesIn(connectionStatus.getInputBytes());
1171
1172         snapshot.setFlowFilesOut(connectionStatus.getOutputCount());
1173         snapshot.setBytesOut(connectionStatus.getOutputBytes());
1174
1175         if (connectionStatus.getBackPressureObjectThreshold() > 0) {
1176             snapshot.setPercentUseCount(Math.min(100, StatusMerger.getUtilization(connectionStatus.getQueuedCount(), connectionStatus.getBackPressureObjectThreshold())));
1177         }
1178         if (connectionStatus.getBackPressureBytesThreshold() > 0) {
1179             snapshot.setPercentUseBytes(Math.min(100, StatusMerger.getUtilization(connectionStatus.getQueuedBytes(), connectionStatus.getBackPressureBytesThreshold())));
1180         }
1181
1182         StatusMerger.updatePrettyPrintedFields(snapshot);
1183
1184         return connectionStatusDto;
1185     }
1186
1187     public ProcessorStatusDTO createProcessorStatusDto(final ProcessorStatus procStatus) {
1188         final ProcessorStatusDTO dto = new ProcessorStatusDTO();
1189         dto.setId(procStatus.getId());
1190         dto.setGroupId(procStatus.getGroupId());
1191         dto.setName(procStatus.getName());
1192         dto.setStatsLastRefreshed(new Date());
1193         dto.setRunStatus(procStatus.getRunStatus().toString());
1194
1195         final ProcessorStatusSnapshotDTO snapshot = new ProcessorStatusSnapshotDTO();
1196         dto.setAggregateSnapshot(snapshot);
1197
1198         snapshot.setId(procStatus.getId());
1199         snapshot.setGroupId(procStatus.getGroupId());
1200         snapshot.setName(procStatus.getName());
1201
1202         snapshot.setFlowFilesOut(procStatus.getOutputCount());
1203         snapshot.setBytesOut(procStatus.getOutputBytes());
1204
1205         snapshot.setFlowFilesIn(procStatus.getInputCount());
1206         snapshot.setBytesIn(procStatus.getInputBytes());
1207
1208         snapshot.setBytesRead(procStatus.getBytesRead());
1209         snapshot.setBytesWritten(procStatus.getBytesWritten());
1210
1211         snapshot.setTaskCount(procStatus.getInvocations());
1212         snapshot.setTasksDurationNanos(procStatus.getProcessingNanos());
1213         snapshot.setTasksDuration(FormatUtils.formatHoursMinutesSeconds(procStatus.getProcessingNanos(), TimeUnit.NANOSECONDS));
1214
1215         // determine the run status
1216         snapshot.setRunStatus(procStatus.getRunStatus().toString());
1217         snapshot.setExecutionNode(procStatus.getExecutionNode().toString());
1218
1219         snapshot.setActiveThreadCount(procStatus.getActiveThreadCount());
1220         snapshot.setTerminatedThreadCount(procStatus.getTerminatedThreadCount());
1221         snapshot.setType(procStatus.getType());
1222
1223         StatusMerger.updatePrettyPrintedFields(snapshot);
1224         return dto;
1225     }
1226
1227     /**
1228      * Creates a PortStatusDTO for the specified PortStatus.
1229      *
1230      * @param portStatus status
1231      * @return dto
1232      */
1233     public PortStatusDTO createPortStatusDto(final PortStatus portStatus) {
1234         final PortStatusDTO dto = new PortStatusDTO();
1235         dto.setId(portStatus.getId());
1236         dto.setGroupId(portStatus.getGroupId());
1237         dto.setName(portStatus.getName());
1238         dto.setRunStatus(portStatus.getRunStatus().toString());
1239         dto.setTransmitting(portStatus.isTransmitting());
1240         dto.setStatsLastRefreshed(new Date());
1241
1242         final PortStatusSnapshotDTO snapshot = new PortStatusSnapshotDTO();
1243         dto.setAggregateSnapshot(snapshot);
1244
1245         snapshot.setId(portStatus.getId());
1246         snapshot.setGroupId(portStatus.getGroupId());
1247         snapshot.setName(portStatus.getName());
1248         snapshot.setRunStatus(portStatus.getRunStatus().toString());
1249
1250         snapshot.setActiveThreadCount(portStatus.getActiveThreadCount());
1251         snapshot.setFlowFilesOut(portStatus.getOutputCount());
1252         snapshot.setBytesOut(portStatus.getOutputBytes());
1253
1254         snapshot.setFlowFilesIn(portStatus.getInputCount());
1255         snapshot.setBytesIn(portStatus.getInputBytes());
1256         StatusMerger.updatePrettyPrintedFields(snapshot);
1257
1258         return dto;
1259     }
1260
1261     /**
1262      * Copies the specified snippet.
1263      *
1264      * @param originalSnippet snippet
1265      * @return dto
1266      */
1267     public FlowSnippetDTO copySnippetContents(final FlowSnippetDTO originalSnippet) {
1268         final FlowSnippetDTO copySnippet = new FlowSnippetDTO();
1269
1270         if (originalSnippet.getConnections() != null) {
1271             for (final ConnectionDTO connection : originalSnippet.getConnections()) {
1272                 copySnippet.getConnections().add(copy(connection));
1273             }
1274         }
1275         if (originalSnippet.getInputPorts() != null) {
1276             for (final PortDTO port : originalSnippet.getInputPorts()) {
1277                 copySnippet.getInputPorts().add(copy(port));
1278             }
1279         }
1280         if (originalSnippet.getOutputPorts() != null) {
1281             for (final PortDTO port : originalSnippet.getOutputPorts()) {
1282                 copySnippet.getOutputPorts().add(copy(port));
1283             }
1284         }
1285         if (originalSnippet.getProcessGroups() != null) {
1286             for (final ProcessGroupDTO processGroup : originalSnippet.getProcessGroups()) {
1287                 copySnippet.getProcessGroups().add(copy(processGroup, true));
1288             }
1289         }
1290         if (originalSnippet.getProcessors() != null) {
1291             for (final ProcessorDTO processor : originalSnippet.getProcessors()) {
1292                 copySnippet.getProcessors().add(copy(processor));
1293             }
1294         }
1295         if (originalSnippet.getLabels() != null) {
1296             for (final LabelDTO label : originalSnippet.getLabels()) {
1297                 copySnippet.getLabels().add(copy(label));
1298             }
1299         }
1300         if (originalSnippet.getFunnels() != null) {
1301             for (final FunnelDTO funnel : originalSnippet.getFunnels()) {
1302                 copySnippet.getFunnels().add(copy(funnel));
1303             }
1304         }
1305         if (originalSnippet.getRemoteProcessGroups() != null) {
1306             for (final RemoteProcessGroupDTO remoteGroup : originalSnippet.getRemoteProcessGroups()) {
1307                 copySnippet.getRemoteProcessGroups().add(copy(remoteGroup));
1308             }
1309         }
1310         if (originalSnippet.getControllerServices() != null) {
1311             for (final ControllerServiceDTO controllerService : originalSnippet.getControllerServices()) {
1312                 copySnippet.getControllerServices().add(copy(controllerService));
1313             }
1314         }
1315
1316         return copySnippet;
1317     }
1318
1319     /**
1320      * Creates a PortDTO from the specified Port.
1321      *
1322      * @param port port
1323      * @return dto
1324      */
1325     public PortDTO createPortDto(final Port port) {
1326         if (port == null) {
1327             return null;
1328         }
1329
1330         final PortDTO dto = new PortDTO();
1331         dto.setId(port.getIdentifier());
1332         dto.setPosition(createPositionDto(port.getPosition()));
1333         dto.setName(port.getName());
1334         dto.setComments(port.getComments());
1335         dto.setConcurrentlySchedulableTaskCount(port.getMaxConcurrentTasks());
1336         dto.setParentGroupId(port.getProcessGroup().getIdentifier());
1337         dto.setState(port.getScheduledState().toString());
1338         dto.setType(port.getConnectableType().name());
1339         dto.setVersionedComponentId(port.getVersionedComponentId().orElse(null));
1340
1341         // if this port is on the root group, determine if its actually connected to another nifi
1342         if (port instanceof RootGroupPort) {
1343             final RootGroupPort rootGroupPort = (RootGroupPort) port;
1344             dto.setTransmitting(rootGroupPort.isTransmitting());
1345             dto.setGroupAccessControl(rootGroupPort.getGroupAccessControl());
1346             dto.setUserAccessControl(rootGroupPort.getUserAccessControl());
1347         }
1348
1349         final Collection<ValidationResult> validationErrors = port.getValidationErrors();
1350         if (validationErrors != null && !validationErrors.isEmpty()) {
1351             final List<String> errors = new ArrayList<>();
1352             for (final ValidationResult validationResult : validationErrors) {
1353                 errors.add(validationResult.toString());
1354             }
1355
1356             dto.setValidationErrors(errors);
1357         }
1358
1359         return dto;
1360     }
1361
1362     public ReportingTaskDTO createReportingTaskDto(final ReportingTaskNode reportingTaskNode) {
1363         final BundleCoordinate bundleCoordinate = reportingTaskNode.getBundleCoordinate();
1364         final List<Bundle> compatibleBundles = extensionManager.getBundles(reportingTaskNode.getCanonicalClassName()).stream().filter(bundle -> {
1365             final BundleCoordinate coordinate = bundle.getBundleDetails().getCoordinate();
1366             return bundleCoordinate.getGroup().equals(coordinate.getGroup()) && bundleCoordinate.getId().equals(coordinate.getId());
1367         }).collect(Collectors.toList());
1368
1369         final ReportingTaskDTO dto = new ReportingTaskDTO();
1370         dto.setId(reportingTaskNode.getIdentifier());
1371         dto.setName(reportingTaskNode.getName());
1372         dto.setType(reportingTaskNode.getCanonicalClassName());
1373         dto.setBundle(createBundleDto(bundleCoordinate));
1374         dto.setSchedulingStrategy(reportingTaskNode.getSchedulingStrategy().name());
1375         dto.setSchedulingPeriod(reportingTaskNode.getSchedulingPeriod());
1376         dto.setState(reportingTaskNode.getScheduledState().name());
1377         dto.setActiveThreadCount(reportingTaskNode.getActiveThreadCount());
1378         dto.setAnnotationData(reportingTaskNode.getAnnotationData());
1379         dto.setComments(reportingTaskNode.getComments());
1380         dto.setPersistsState(reportingTaskNode.getReportingTask().getClass().isAnnotationPresent(Stateful.class));
1381         dto.setRestricted(reportingTaskNode.isRestricted());
1382         dto.setDeprecated(reportingTaskNode.isDeprecated());
1383         dto.setExtensionMissing(reportingTaskNode.isExtensionMissing());
1384         dto.setMultipleVersionsAvailable(compatibleBundles.size() > 1);
1385
1386         final Map<String, String> defaultSchedulingPeriod = new HashMap<>();
1387         defaultSchedulingPeriod.put(SchedulingStrategy.TIMER_DRIVEN.name(), SchedulingStrategy.TIMER_DRIVEN.getDefaultSchedulingPeriod());
1388         defaultSchedulingPeriod.put(SchedulingStrategy.CRON_DRIVEN.name(), SchedulingStrategy.CRON_DRIVEN.getDefaultSchedulingPeriod());
1389         dto.setDefaultSchedulingPeriod(defaultSchedulingPeriod);
1390
1391         // sort a copy of the properties
1392         final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() {
1393             @Override
1394             public int compare(final PropertyDescriptor o1, final PropertyDescriptor o2) {
1395                 return Collator.getInstance(Locale.US).compare(o1.getName(), o2.getName());
1396             }
1397         });
1398         sortedProperties.putAll(reportingTaskNode.getProperties());
1399
1400         // get the property order from the reporting task
1401         final ReportingTask reportingTask = reportingTaskNode.getReportingTask();
1402         final Map<PropertyDescriptor, String> orderedProperties = new LinkedHashMap<>();
1403         final List<PropertyDescriptor> descriptors = reportingTask.getPropertyDescriptors();
1404         if (descriptors != null && !descriptors.isEmpty()) {
1405             for (final PropertyDescriptor descriptor : descriptors) {
1406                 orderedProperties.put(descriptor, null);
1407             }
1408         }
1409         orderedProperties.putAll(sortedProperties);
1410
1411         // build the descriptor and property dtos
1412         dto.setDescriptors(new LinkedHashMap<String, PropertyDescriptorDTO>());
1413         dto.setProperties(new LinkedHashMap<String, String>());
1414         for (final Map.Entry<PropertyDescriptor, String> entry : orderedProperties.entrySet()) {
1415             final PropertyDescriptor descriptor = entry.getKey();
1416
1417             // store the property descriptor
1418             dto.getDescriptors().put(descriptor.getName(), createPropertyDescriptorDto(descriptor, null));
1419
1420             // determine the property value - don't include sensitive properties
1421             String propertyValue = entry.getValue();
1422             if (propertyValue != null && descriptor.isSensitive()) {
1423                 propertyValue = SENSITIVE_VALUE_MASK;
1424             }
1425
1426             // set the property value
1427             dto.getProperties().put(descriptor.getName(), propertyValue);
1428         }
1429
1430         final ValidationStatus validationStatus = reportingTaskNode.getValidationStatus(1, TimeUnit.MILLISECONDS);
1431         dto.setValidationStatus(validationStatus.name());
1432
1433         // add the validation errors
1434         final Collection<ValidationResult> validationErrors = reportingTaskNode.getValidationErrors();
1435         if (validationErrors != null && !validationErrors.isEmpty()) {
1436             final List<String> errors = new ArrayList<>();
1437             for (final ValidationResult validationResult : validationErrors) {
1438                 errors.add(validationResult.toString());
1439             }
1440
1441             dto.setValidationErrors(errors);
1442         }
1443
1444         return dto;
1445     }
1446
1447     public ControllerServiceDTO createControllerServiceDto(final ControllerServiceNode controllerServiceNode) {
1448         final BundleCoordinate bundleCoordinate = controllerServiceNode.getBundleCoordinate();
1449         final List<Bundle> compatibleBundles = extensionManager.getBundles(controllerServiceNode.getCanonicalClassName()).stream().filter(bundle -> {
1450             final BundleCoordinate coordinate = bundle.getBundleDetails().getCoordinate();
1451             return bundleCoordinate.getGroup().equals(coordinate.getGroup()) && bundleCoordinate.getId().equals(coordinate.getId());
1452         }).collect(Collectors.toList());
1453
1454         final ControllerServiceDTO dto = new ControllerServiceDTO();
1455         dto.setId(controllerServiceNode.getIdentifier());
1456         dto.setParentGroupId(controllerServiceNode.getProcessGroup() == null ? null : controllerServiceNode.getProcessGroup().getIdentifier());
1457         dto.setName(controllerServiceNode.getName());
1458         dto.setType(controllerServiceNode.getCanonicalClassName());
1459         dto.setBundle(createBundleDto(bundleCoordinate));
1460         dto.setControllerServiceApis(createControllerServiceApiDto(controllerServiceNode.getControllerServiceImplementation().getClass()));
1461         dto.setState(controllerServiceNode.getState().name());
1462         dto.setAnnotationData(controllerServiceNode.getAnnotationData());
1463         dto.setComments(controllerServiceNode.getComments());
1464         dto.setPersistsState(controllerServiceNode.getControllerServiceImplementation().getClass().isAnnotationPresent(Stateful.class));
1465         dto.setRestricted(controllerServiceNode.isRestricted());
1466         dto.setDeprecated(controllerServiceNode.isDeprecated());
1467         dto.setExtensionMissing(controllerServiceNode.isExtensionMissing());
1468         dto.setMultipleVersionsAvailable(compatibleBundles.size() > 1);
1469         dto.setVersionedComponentId(controllerServiceNode.getVersionedComponentId().orElse(null));
1470
1471         // sort a copy of the properties
1472         final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() {
1473             @Override
1474             public int compare(final PropertyDescriptor o1, final PropertyDescriptor o2) {
1475                 return Collator.getInstance(Locale.US).compare(o1.getName(), o2.getName());
1476             }
1477         });
1478         sortedProperties.putAll(controllerServiceNode.getProperties());
1479
1480         // get the property order from the controller service
1481         final ControllerService controllerService = controllerServiceNode.getControllerServiceImplementation();
1482         final Map<PropertyDescriptor, String> orderedProperties = new LinkedHashMap<>();
1483         final List<PropertyDescriptor> descriptors = controllerService.getPropertyDescriptors();
1484         if (descriptors != null && !descriptors.isEmpty()) {
1485             for (final PropertyDescriptor descriptor : descriptors) {
1486                 orderedProperties.put(descriptor, null);
1487             }
1488         }
1489         orderedProperties.putAll(sortedProperties);
1490
1491         // build the descriptor and property dtos
1492         dto.setDescriptors(new LinkedHashMap<String, PropertyDescriptorDTO>());
1493         dto.setProperties(new LinkedHashMap<String, String>());
1494         for (final Map.Entry<PropertyDescriptor, String> entry : orderedProperties.entrySet()) {
1495             final PropertyDescriptor descriptor = entry.getKey();
1496
1497             // store the property descriptor
1498             final String groupId = controllerServiceNode.getProcessGroup() == null ? null : controllerServiceNode.getProcessGroup().getIdentifier();
1499             dto.getDescriptors().put(descriptor.getName(), createPropertyDescriptorDto(descriptor, groupId));
1500
1501             // determine the property value - don't include sensitive properties
1502             String propertyValue = entry.getValue();
1503             if (propertyValue != null && descriptor.isSensitive()) {
1504                 propertyValue = SENSITIVE_VALUE_MASK;
1505             }
1506
1507             // set the property value
1508             dto.getProperties().put(descriptor.getName(), propertyValue);
1509         }
1510
1511         dto.setValidationStatus(controllerServiceNode.getValidationStatus(1, TimeUnit.MILLISECONDS).name());
1512
1513         // add the validation errors
1514         final Collection<ValidationResult> validationErrors = controllerServiceNode.getValidationErrors();
1515         if (validationErrors != null && !validationErrors.isEmpty()) {
1516             final List<String> errors = new ArrayList<>();
1517             for (final ValidationResult validationResult : validationErrors) {
1518                 errors.add(validationResult.toString());
1519             }
1520
1521             dto.setValidationErrors(errors);
1522         }
1523
1524         return dto;
1525     }
1526
1527     public ControllerServiceReferencingComponentDTO createControllerServiceReferencingComponentDTO(final ComponentNode component) {
1528         final ControllerServiceReferencingComponentDTO dto = new ControllerServiceReferencingComponentDTO();
1529         dto.setId(component.getIdentifier());
1530         dto.setName(component.getName());
1531
1532         String processGroupId = null;
1533         List<PropertyDescriptor> propertyDescriptors = null;
1534         Collection<ValidationResult> validationErrors = null;
1535         if (component instanceof ProcessorNode) {
1536             final ProcessorNode node = ((ProcessorNode) component);
1537             dto.setGroupId(node.getProcessGroup().getIdentifier());
1538             dto.setState(node.getScheduledState().name());
1539             dto.setActiveThreadCount(node.getActiveThreadCount());
1540             dto.setType(node.getComponentType());
1541             dto.setReferenceType(Processor.class.getSimpleName());
1542
1543             propertyDescriptors = node.getProcessor().getPropertyDescriptors();
1544             validationErrors = node.getValidationErrors();
1545             processGroupId = node.getProcessGroup().getIdentifier();
1546         } else if (component instanceof ControllerServiceNode) {
1547             final ControllerServiceNode node = ((ControllerServiceNode) component);
1548             dto.setState(node.getState().name());
1549             dto.setType(node.getComponentType());
1550             dto.setReferenceType(ControllerService.class.getSimpleName());
1551
1552             propertyDescriptors = node.getControllerServiceImplementation().getPropertyDescriptors();
1553             validationErrors = node.getValidationErrors();
1554             processGroupId = node.getProcessGroup() == null ? null : node.getProcessGroup().getIdentifier();
1555         } else if (component instanceof ReportingTaskNode) {
1556             final ReportingTaskNode node = ((ReportingTaskNode) component);
1557             dto.setState(node.getScheduledState().name());
1558             dto.setActiveThreadCount(node.getActiveThreadCount());
1559             dto.setType(node.getComponentType());
1560             dto.setReferenceType(ReportingTask.class.getSimpleName());
1561
1562             propertyDescriptors = node.getReportingTask().getPropertyDescriptors();
1563             validationErrors = node.getValidationErrors();
1564             processGroupId = null;
1565         }
1566
1567         // ensure descriptors is non null
1568         if (propertyDescriptors == null) {
1569             propertyDescriptors = new ArrayList<>();
1570         }
1571
1572         // process properties unconditionally since dynamic properties are available here and not in getPropertyDescriptors
1573         final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() {
1574             @Override
1575             public int compare(final PropertyDescriptor o1, final PropertyDescriptor o2) {
1576                 return Collator.getInstance(Locale.US).compare(o1.getName(), o2.getName());
1577             }
1578         });
1579         sortedProperties.putAll(component.getProperties());
1580
1581         final Map<PropertyDescriptor, String> orderedProperties = new LinkedHashMap<>();
1582         for (final PropertyDescriptor descriptor : propertyDescriptors) {
1583             orderedProperties.put(descriptor, null);
1584         }
1585         orderedProperties.putAll(sortedProperties);
1586
1587         // build the descriptor and property dtos
1588         dto.setDescriptors(new LinkedHashMap<String, PropertyDescriptorDTO>());
1589         dto.setProperties(new LinkedHashMap<String, String>());
1590         for (final Map.Entry<PropertyDescriptor, String> entry : orderedProperties.entrySet()) {
1591             final PropertyDescriptor descriptor = entry.getKey();
1592
1593             // store the property descriptor
1594             dto.getDescriptors().put(descriptor.getName(), createPropertyDescriptorDto(descriptor, processGroupId));
1595
1596             // determine the property value - don't include sensitive properties
1597             String propertyValue = entry.getValue();
1598             if (propertyValue != null && descriptor.isSensitive()) {
1599                 propertyValue = SENSITIVE_VALUE_MASK;
1600             }
1601
1602             // set the property value
1603             dto.getProperties().put(descriptor.getName(), propertyValue);
1604         }
1605
1606         if (validationErrors != null && !validationErrors.isEmpty()) {
1607             final List<String> errors = new ArrayList<>();
1608             for (final ValidationResult validationResult : validationErrors) {
1609                 errors.add(validationResult.toString());
1610             }
1611
1612             dto.setValidationErrors(errors);
1613         }
1614
1615         return dto;
1616     }
1617
1618     public RemoteProcessGroupPortDTO createRemoteProcessGroupPortDto(final RemoteGroupPort port) {
1619         if (port == null) {
1620             return null;
1621         }
1622
1623         final RemoteProcessGroupPortDTO dto = new RemoteProcessGroupPortDTO();
1624         dto.setId(port.getIdentifier());
1625         dto.setGroupId(port.getRemoteProcessGroup().getIdentifier());
1626         dto.setTargetId(port.getTargetIdentifier());
1627         dto.setName(port.getName());
1628         dto.setComments(port.getComments());
1629         dto.setTransmitting(port.isRunning());
1630         dto.setTargetRunning(port.isTargetRunning());
1631         dto.setConcurrentlySchedulableTaskCount(port.getMaxConcurrentTasks());
1632         dto.setUseCompression(port.isUseCompression());
1633         dto.setExists(port.getTargetExists());
1634         dto.setVersionedComponentId(port.getVersionedComponentId().orElse(null));
1635
1636         final BatchSettingsDTO batchDTO = new BatchSettingsDTO();
1637         batchDTO.setCount(port.getBatchCount());
1638         batchDTO.setSize(port.getBatchSize());
1639         batchDTO.setDuration(port.getBatchDuration());
1640         dto.setBatchSettings(batchDTO);
1641
1642         // determine if this port is currently connected to another component locally
1643         if (ConnectableType.REMOTE_OUTPUT_PORT.equals(port.getConnectableType())) {
1644             dto.setConnected(!port.getConnections().isEmpty());
1645         } else {
1646             dto.setConnected(port.hasIncomingConnection());
1647         }
1648
1649         return dto;
1650     }
1651
1652     /**
1653      * Creates a RemoteProcessGroupDTO from the specified RemoteProcessGroup.
1654      *
1655      * @param group group
1656      * @return dto
1657      */
1658     public RemoteProcessGroupDTO createRemoteProcessGroupDto(final RemoteProcessGroup group) {
1659         if (group == null) {
1660             return null;
1661         }
1662
1663         final Set<RemoteProcessGroupPortDTO> inputPorts = new HashSet<>();
1664         final Set<RemoteProcessGroupPortDTO> outputPorts = new HashSet<>();
1665
1666         int activeRemoteInputPortCount = 0;
1667         int inactiveRemoteInputPortCount = 0;
1668         for (final Port port : group.getInputPorts()) {
1669             inputPorts.add(createRemoteProcessGroupPortDto((RemoteGroupPort) port));
1670
1671             if (port.hasIncomingConnection()) {
1672                 if (port.isRunning()) {
1673                     activeRemoteInputPortCount++;
1674                 } else {
1675                     inactiveRemoteInputPortCount++;
1676                 }
1677             }
1678         }
1679
1680         int activeRemoteOutputPortCount = 0;
1681         int inactiveRemoteOutputPortCount = 0;
1682         for (final Port port : group.getOutputPorts()) {
1683             outputPorts.add(createRemoteProcessGroupPortDto((RemoteGroupPort) port));
1684
1685             if (!port.getConnections().isEmpty()) {
1686                 if (port.isRunning()) {
1687                     activeRemoteOutputPortCount++;
1688                 } else {
1689                     inactiveRemoteOutputPortCount++;
1690                 }
1691             }
1692         }
1693
1694         final RemoteProcessGroupContentsDTO contents = new RemoteProcessGroupContentsDTO();
1695         contents.setInputPorts(inputPorts);
1696         contents.setOutputPorts(outputPorts);
1697
1698         final RemoteProcessGroupDTO dto = new RemoteProcessGroupDTO();
1699         dto.setId(group.getIdentifier());
1700         dto.setName(group.getName());
1701         dto.setPosition(createPositionDto(group.getPosition()));
1702         dto.setComments(group.getComments());
1703         dto.setTransmitting(group.isTransmitting());
1704         dto.setCommunicationsTimeout(group.getCommunicationsTimeout());
1705         dto.setYieldDuration(group.getYieldDuration());
1706         dto.setParentGroupId(group.getProcessGroup().getIdentifier());
1707         dto.setTargetUris(group.getTargetUris());
1708         dto.setFlowRefreshed(group.getLastRefreshTime());
1709         dto.setContents(contents);
1710         dto.setTransportProtocol(group.getTransportProtocol().name());
1711         dto.setProxyHost(group.getProxyHost());
1712         dto.setProxyPort(group.getProxyPort());
1713         dto.setProxyUser(group.getProxyUser());
1714         if (!StringUtils.isEmpty(group.getProxyPassword())) {
1715             dto.setProxyPassword(SENSITIVE_VALUE_MASK);
1716         }
1717
1718         // only specify the secure flag if we know the target system has site to site enabled
1719         if (group.isSiteToSiteEnabled()) {
1720             dto.setTargetSecure(group.getSecureFlag());
1721         }
1722
1723         if (group.getAuthorizationIssue() != null) {
1724             dto.setAuthorizationIssues(Arrays.asList(group.getAuthorizationIssue()));
1725         }
1726
1727         final Collection<ValidationResult> validationErrors = group.validate();
1728         if (validationErrors != null && !validationErrors.isEmpty()) {
1729             final List<String> errors = new ArrayList<>();
1730             for (final ValidationResult validationResult : validationErrors) {
1731                 errors.add(validationResult.toString());
1732             }
1733
1734             dto.setValidationErrors(errors);
1735         }
1736
1737         dto.setLocalNetworkInterface(group.getNetworkInterface());
1738
1739         dto.setActiveRemoteInputPortCount(activeRemoteInputPortCount);
1740         dto.setInactiveRemoteInputPortCount(inactiveRemoteInputPortCount);
1741         dto.setActiveRemoteOutputPortCount(activeRemoteOutputPortCount);
1742         dto.setInactiveRemoteOutputPortCount(inactiveRemoteOutputPortCount);
1743         dto.setVersionedComponentId(group.getVersionedComponentId().orElse(null));
1744
1745         final RemoteProcessGroupCounts counts = group.getCounts();
1746         if (counts != null) {
1747             dto.setInputPortCount(counts.getInputPortCount());
1748             dto.setOutputPortCount(counts.getOutputPortCount());
1749         }
1750
1751         return dto;
1752     }
1753
1754     /**
1755      * Creates a FlowBreadcrumbEntity from the specified parent ProcessGroup.
1756      *
1757      * @param group group
1758      * @return dto
1759      */
1760     private FlowBreadcrumbEntity createBreadcrumbEntity(final ProcessGroup group) {
1761         if (group == null) {
1762             return null;
1763         }
1764
1765         final FlowBreadcrumbDTO dto = createBreadcrumbDto(group);
1766         final PermissionsDTO permissions = createPermissionsDto(group);
1767         final FlowBreadcrumbEntity entity = entityFactory.createFlowBreadcrumbEntity(dto, permissions);
1768
1769         if (group.getParent() != null) {
1770             entity.setParentBreadcrumb(createBreadcrumbEntity(group.getParent()));
1771         }
1772
1773         return entity;
1774     }
1775
1776     /**
1777      * Creates a FlowBreadcrumbDTO from the specified parent ProcessGroup.
1778      *
1779      * @param group group
1780      * @return dto
1781      */
1782     private FlowBreadcrumbDTO createBreadcrumbDto(final ProcessGroup group) {
1783         if (group == null) {
1784             return null;
1785         }
1786
1787         final FlowBreadcrumbDTO dto = new FlowBreadcrumbDTO();
1788         dto.setId(group.getIdentifier());
1789         dto.setName(group.getName());
1790
1791         final VersionControlInformationDTO versionControlInformation = createVersionControlInformationDto(group);
1792         dto.setVersionControlInformation(versionControlInformation);
1793
1794         return dto;
1795     }
1796
1797     public ComponentReferenceDTO createComponentReferenceDto(final Authorizable authorizable) {
1798         if (authorizable == null || !(authorizable instanceof ComponentAuthorizable)) {
1799             return null;
1800         }
1801
1802         final ComponentAuthorizable componentAuthorizable = (ComponentAuthorizable) authorizable;
1803         final ComponentReferenceDTO dto = new ComponentReferenceDTO();
1804         dto.setId(componentAuthorizable.getIdentifier());
1805         dto.setParentGroupId(componentAuthorizable.getProcessGroupIdentifier());
1806         dto.setName(authorizable.getResource().getName());
1807
1808         return dto;
1809     }
1810
1811     public AccessPolicySummaryDTO createAccessPolicySummaryDto(final AccessPolicy accessPolicy, final ComponentReferenceEntity componentReference) {
1812         if (accessPolicy == null) {
1813             return null;
1814         }
1815
1816         final AccessPolicySummaryDTO dto = new AccessPolicySummaryDTO();
1817         dto.setId(accessPolicy.getIdentifier());
1818         dto.setResource(accessPolicy.getResource());
1819         dto.setAction(accessPolicy.getAction().toString());
1820         dto.setConfigurable(AuthorizerCapabilityDetection.isAccessPolicyConfigurable(authorizer, accessPolicy));
1821         dto.setComponentReference(componentReference);
1822         return dto;
1823     }
1824
1825     public AccessPolicyDTO createAccessPolicyDto(final AccessPolicy accessPolicy, final Set<TenantEntity> userGroups,
1826                                                  final Set<TenantEntity> users, final ComponentReferenceEntity componentReference) {
1827
1828         if (accessPolicy == null) {
1829             return null;
1830         }
1831
1832         final AccessPolicyDTO dto = new AccessPolicyDTO();
1833         dto.setUserGroups(userGroups);
1834         dto.setUsers(users);
1835         dto.setId(accessPolicy.getIdentifier());
1836         dto.setResource(accessPolicy.getResource());
1837         dto.setAction(accessPolicy.getAction().toString());
1838         dto.setConfigurable(AuthorizerCapabilityDetection.isAccessPolicyConfigurable(authorizer, accessPolicy));
1839         dto.setComponentReference(componentReference);
1840         return dto;
1841     }
1842
1843     /**
1844      * Creates the PermissionsDTO based on the specified Authorizable.
1845      *
1846      * @param authorizable authorizable
1847      * @return dto
1848      */
1849     public PermissionsDTO createPermissionsDto(final Authorizable authorizable) {
1850         return createPermissionsDto(authorizable, NiFiUserUtils.getNiFiUser());
1851     }
1852
1853     /**
1854      * Creates the PermissionsDTO based on the specified Authorizable for the given user
1855      *
1856      * @param authorizable authorizable
1857      * @param user the NiFi User for which the Permissions are being created
1858      * @return dto
1859      */
1860     public PermissionsDTO createPermissionsDto(final Authorizable authorizable, final NiFiUser user) {
1861         final PermissionsDTO dto = new PermissionsDTO();
1862         dto.setCanRead(authorizable.isAuthorized(authorizer, RequestAction.READ, user));
1863         dto.setCanWrite(authorizable.isAuthorized(authorizer, RequestAction.WRITE, user));
1864         return dto;
1865     }
1866
1867     public AffectedComponentEntity createAffectedComponentEntity(final ProcessorEntity processorEntity) {
1868         if (processorEntity == null) {
1869             return null;
1870         }
1871
1872         final AffectedComponentEntity component = new AffectedComponentEntity();
1873         component.setBulletins(processorEntity.getBulletins());
1874         component.setId(processorEntity.getId());
1875         component.setPermissions(processorEntity.getPermissions());
1876         component.setPosition(processorEntity.getPosition());
1877         component.setRevision(processorEntity.getRevision());
1878         component.setUri(processorEntity.getUri());
1879
1880         final ProcessorDTO processorDto = processorEntity.getComponent();
1881         final AffectedComponentDTO componentDto = new AffectedComponentDTO();
1882         componentDto.setId(processorDto.getId());
1883         componentDto.setName(processorDto.getName());
1884         componentDto.setProcessGroupId(processorDto.getParentGroupId());
1885         componentDto.setReferenceType(AffectedComponentDTO.COMPONENT_TYPE_PROCESSOR);
1886         componentDto.setState(processorDto.getState());
1887         componentDto.setValidationErrors(processorDto.getValidationErrors());
1888         component.setComponent(componentDto);
1889
1890         return component;
1891     }
1892
1893     public AffectedComponentEntity createAffectedComponentEntity(final PortEntity portEntity, final String referenceType) {
1894         if (portEntity == null) {
1895             return null;
1896         }
1897
1898         final AffectedComponentEntity component = new AffectedComponentEntity();
1899         component.setBulletins(portEntity.getBulletins());
1900         component.setId(portEntity.getId());
1901         component.setPermissions(portEntity.getPermissions());
1902         component.setPosition(portEntity.getPosition());
1903         component.setRevision(portEntity.getRevision());
1904         component.setUri(portEntity.getUri());
1905
1906         final PortDTO portDto = portEntity.getComponent();
1907         final AffectedComponentDTO componentDto = new AffectedComponentDTO();
1908         componentDto.setId(portDto.getId());
1909         componentDto.setName(portDto.getName());
1910         componentDto.setProcessGroupId(portDto.getParentGroupId());
1911         componentDto.setReferenceType(referenceType);
1912         componentDto.setState(portDto.getState());
1913         componentDto.setValidationErrors(portDto.getValidationErrors());
1914         component.setComponent(componentDto);
1915
1916         return component;
1917     }
1918
1919     public AffectedComponentEntity createAffectedComponentEntity(final ControllerServiceEntity serviceEntity) {
1920         if (serviceEntity == null) {
1921             return null;
1922         }
1923
1924         final AffectedComponentEntity component = new AffectedComponentEntity();
1925         component.setBulletins(serviceEntity.getBulletins());
1926         component.setId(serviceEntity.getId());
1927         component.setPermissions(serviceEntity.getPermissions());
1928         component.setPosition(serviceEntity.getPosition());
1929         component.setRevision(serviceEntity.getRevision());
1930         component.setUri(serviceEntity.getUri());
1931
1932         final ControllerServiceDTO serviceDto = serviceEntity.getComponent();
1933         final AffectedComponentDTO componentDto = new AffectedComponentDTO();
1934         componentDto.setId(serviceDto.getId());
1935         componentDto.setName(serviceDto.getName());
1936         componentDto.setProcessGroupId(serviceDto.getParentGroupId());
1937         componentDto.setReferenceType(AffectedComponentDTO.COMPONENT_TYPE_CONTROLLER_SERVICE);
1938         componentDto.setState(serviceDto.getState());
1939         componentDto.setValidationErrors(serviceDto.getValidationErrors());
1940         component.setComponent(componentDto);
1941
1942         return component;
1943     }
1944
1945     public AffectedComponentEntity createAffectedComponentEntity(final RemoteProcessGroupPortDTO remotePortDto, final String referenceType, final RemoteProcessGroupEntity rpgEntity) {
1946         if (remotePortDto == null) {
1947             return null;
1948         }
1949
1950         final AffectedComponentEntity component = new AffectedComponentEntity();
1951         component.setId(remotePortDto.getId());
1952         component.setPermissions(rpgEntity.getPermissions());
1953         component.setRevision(rpgEntity.getRevision());
1954         component.setUri(rpgEntity.getUri());
1955
1956         final AffectedComponentDTO componentDto = new AffectedComponentDTO();
1957         componentDto.setId(remotePortDto.getId());
1958         componentDto.setName(remotePortDto.getName());
1959         componentDto.setProcessGroupId(remotePortDto.getGroupId());
1960         componentDto.setReferenceType(referenceType);
1961         componentDto.setState(remotePortDto.isTransmitting() ? "Running" : "Stopped");
1962         component.setComponent(componentDto);
1963
1964         return component;
1965     }
1966
1967
1968     public AffectedComponentDTO createAffectedComponentDto(final ComponentNode component) {
1969         final AffectedComponentDTO dto = new AffectedComponentDTO();
1970         dto.setId(component.getIdentifier());
1971         dto.setName(component.getName());
1972         dto.setProcessGroupId(component.getProcessGroupIdentifier());
1973
1974         if (component instanceof ProcessorNode) {
1975             final ProcessorNode node = ((ProcessorNode) component);
1976             dto.setState(node.getScheduledState().name());
1977             dto.setActiveThreadCount(node.getActiveThreadCount());
1978             dto.setReferenceType(AffectedComponentDTO.COMPONENT_TYPE_PROCESSOR);
1979         } else if (component instanceof ControllerServiceNode) {
1980             final ControllerServiceNode node = ((ControllerServiceNode) component);
1981             dto.setState(node.getState().name());
1982             dto.setReferenceType(AffectedComponentDTO.COMPONENT_TYPE_CONTROLLER_SERVICE);
1983         }
1984
1985         final Collection<ValidationResult> validationErrors = component.getValidationErrors();
1986         if (validationErrors != null && !validationErrors.isEmpty()) {
1987             final List<String> errors = new ArrayList<>();
1988             for (final ValidationResult validationResult : validationErrors) {
1989                 errors.add(validationResult.toString());
1990             }
1991
1992             dto.setValidationErrors(errors);
1993         }
1994
1995         return dto;
1996     }
1997
1998     /**
1999      * Creates a ProcessGroupDTO from the specified ProcessGroup.
2000      *
2001      * @param group group
2002      * @return dto
2003      */
2004     public ProcessGroupDTO createProcessGroupDto(final ProcessGroup group) {
2005         return createProcessGroupDto(group, false);
2006     }
2007
2008     public ProcessGroupFlowDTO createProcessGroupFlowDto(final ProcessGroup group, final ProcessGroupStatus groupStatus, final RevisionManager revisionManager,
2009                                                          final Function<ProcessGroup, List<BulletinEntity>> getProcessGroupBulletins) {
2010
2011         final ProcessGroupFlowDTO dto = new ProcessGroupFlowDTO();
2012         dto.setId(group.getIdentifier());
2013         dto.setLastRefreshed(new Date());
2014         dto.setBreadcrumb(createBreadcrumbEntity(group));
2015         dto.setFlow(createFlowDto(group, groupStatus, revisionManager, getProcessGroupBulletins));
2016
2017         final ProcessGroup parent = group.getParent();
2018         if (parent != null) {
2019             dto.setParentGroupId(parent.getIdentifier());
2020         }
2021
2022         return dto;
2023     }
2024
2025     public FlowDTO createFlowDto(final ProcessGroup group, final ProcessGroupStatus groupStatus, final FlowSnippetDTO snippet, final RevisionManager revisionManager,
2026                                  final Function<ProcessGroup, List<BulletinEntity>> getProcessGroupBulletins) {
2027         if (snippet == null) {
2028             return null;
2029         }
2030
2031         final FlowDTO flow = new FlowDTO();
2032
2033         for (final ConnectionDTO snippetConnection : snippet.getConnections()) {
2034             final Connection connection = group.getConnection(snippetConnection.getId());
2035
2036             // marshal the actual connection as the snippet is pruned
2037             final ConnectionDTO dto = createConnectionDto(connection);
2038             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(connection.getIdentifier()));
2039             final PermissionsDTO accessPolicy = createPermissionsDto(connection);
2040             final ConnectionStatusDTO status = getComponentStatus(
2041                 () -> groupStatus.getConnectionStatus().stream().filter(connectionStatus -> connection.getIdentifier().equals(connectionStatus.getId())).findFirst().orElse(null),
2042                 connectionStatus -> createConnectionStatusDto(connectionStatus)
2043             );
2044             flow.getConnections().add(entityFactory.createConnectionEntity(dto, revision, accessPolicy, status));
2045         }
2046
2047         for (final FunnelDTO snippetFunnel : snippet.getFunnels()) {
2048             final Funnel funnel = group.getFunnel(snippetFunnel.getId());
2049
2050             // marshal the actual funnel as the snippet is pruned
2051             final FunnelDTO dto = createFunnelDto(funnel);
2052             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(funnel.getIdentifier()));
2053             final PermissionsDTO accessPolicy = createPermissionsDto(funnel);
2054             flow.getFunnels().add(entityFactory.createFunnelEntity(dto, revision, accessPolicy));
2055         }
2056
2057         for (final PortDTO snippetInputPort : snippet.getInputPorts()) {
2058             final Port inputPort = group.getInputPort(snippetInputPort.getId());
2059
2060             // marshal the actual port as the snippet is pruned
2061             final PortDTO dto = createPortDto(inputPort);
2062             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(inputPort.getIdentifier()));
2063             final PermissionsDTO permissions = createPermissionsDto(inputPort);
2064             final PermissionsDTO operatePermissions = createPermissionsDto(new OperationAuthorizable(inputPort));
2065             final PortStatusDTO status = getComponentStatus(
2066                 () -> groupStatus.getInputPortStatus().stream().filter(inputPortStatus -> inputPort.getIdentifier().equals(inputPortStatus.getId())).findFirst().orElse(null),
2067                 inputPortStatus -> createPortStatusDto(inputPortStatus)
2068             );
2069             final List<BulletinDTO> bulletins = createBulletinDtos(bulletinRepository.findBulletinsForSource(inputPort.getIdentifier()));
2070             final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
2071             flow.getInputPorts().add(entityFactory.createPortEntity(dto, revision, permissions, operatePermissions, status, bulletinEntities));
2072         }
2073
2074         for (final PortDTO snippetOutputPort : snippet.getOutputPorts()) {
2075             final Port outputPort = group.getOutputPort(snippetOutputPort.getId());
2076
2077             // marshal the actual port as the snippet is pruned
2078             final PortDTO dto = createPortDto(outputPort);
2079             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(outputPort.getIdentifier()));
2080             final PermissionsDTO permissions = createPermissionsDto(outputPort);
2081             final PermissionsDTO operatePermissions = createPermissionsDto(new OperationAuthorizable(outputPort));
2082             final PortStatusDTO status = getComponentStatus(
2083                 () -> groupStatus.getOutputPortStatus().stream().filter(outputPortStatus -> outputPort.getIdentifier().equals(outputPortStatus.getId())).findFirst().orElse(null),
2084                 outputPortStatus -> createPortStatusDto(outputPortStatus)
2085             );
2086             final List<BulletinDTO> bulletins = createBulletinDtos(bulletinRepository.findBulletinsForSource(outputPort.getIdentifier()));
2087             final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
2088             flow.getOutputPorts().add(entityFactory.createPortEntity(dto, revision, permissions, operatePermissions, status, bulletinEntities));
2089         }
2090
2091         for (final LabelDTO snippetLabel : snippet.getLabels()) {
2092             final Label label = group.getLabel(snippetLabel.getId());
2093
2094             // marshal the actual label as the snippet is pruned
2095             final LabelDTO dto = createLabelDto(label);
2096             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(label.getIdentifier()));
2097             final PermissionsDTO accessPolicy = createPermissionsDto(label);
2098             flow.getLabels().add(entityFactory.createLabelEntity(dto, revision, accessPolicy));
2099         }
2100
2101         for (final ProcessGroupDTO snippetProcessGroup : snippet.getProcessGroups()) {
2102             final ProcessGroup processGroup = group.getProcessGroup(snippetProcessGroup.getId());
2103
2104             // marshal the actual group as the snippet is pruned
2105             final ProcessGroupDTO dto = createProcessGroupDto(processGroup);
2106             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(processGroup.getIdentifier()));
2107             final PermissionsDTO permissions = createPermissionsDto(processGroup);
2108             final ProcessGroupStatusDTO status = getComponentStatus(
2109                 () -> groupStatus.getProcessGroupStatus().stream().filter(processGroupStatus -> processGroup.getIdentifier().equals(processGroupStatus.getId())).findFirst().orElse(null),
2110                 processGroupStatus -> createConciseProcessGroupStatusDto(processGroupStatus)
2111             );
2112             final List<BulletinEntity> bulletins = getProcessGroupBulletins.apply(processGroup);
2113             flow.getProcessGroups().add(entityFactory.createProcessGroupEntity(dto, revision, permissions, status, bulletins));
2114         }
2115
2116         for (final ProcessorDTO snippetProcessor : snippet.getProcessors()) {
2117             final ProcessorNode processor = group.getProcessor(snippetProcessor.getId());
2118
2119             // marshal the actual processor as the snippet is pruned
2120             final ProcessorDTO dto = createProcessorDto(processor);
2121             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(processor.getIdentifier()));
2122             final PermissionsDTO permissions = createPermissionsDto(processor);
2123             final PermissionsDTO operatePermissions = createPermissionsDto(new OperationAuthorizable(processor));
2124             final ProcessorStatusDTO status = getComponentStatus(
2125                 () -> groupStatus.getProcessorStatus().stream().filter(processorStatus -> processor.getIdentifier().equals(processorStatus.getId())).findFirst().orElse(null),
2126                 processorStatus -> createProcessorStatusDto(processorStatus)
2127             );
2128             final List<BulletinDTO> bulletins = createBulletinDtos(bulletinRepository.findBulletinsForSource(processor.getIdentifier()));
2129             final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
2130             flow.getProcessors().add(entityFactory.createProcessorEntity(dto, revision, permissions, operatePermissions, status, bulletinEntities));
2131         }
2132
2133         for (final RemoteProcessGroupDTO snippetRemoteProcessGroup : snippet.getRemoteProcessGroups()) {
2134             final RemoteProcessGroup remoteProcessGroup = group.getRemoteProcessGroup(snippetRemoteProcessGroup.getId());
2135
2136             // marshal the actual rpm as the snippet is pruned
2137             final RemoteProcessGroupDTO dto = createRemoteProcessGroupDto(remoteProcessGroup);
2138             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(remoteProcessGroup.getIdentifier()));
2139             final PermissionsDTO permissions = createPermissionsDto(remoteProcessGroup);
2140             final PermissionsDTO operatePermissions = createPermissionsDto(new OperationAuthorizable(remoteProcessGroup));
2141             final RemoteProcessGroupStatusDTO status = getComponentStatus(
2142                 () -> groupStatus.getRemoteProcessGroupStatus().stream().filter(rpgStatus -> remoteProcessGroup.getIdentifier().equals(rpgStatus.getId())).findFirst().orElse(null),
2143                 remoteProcessGroupStatus -> createRemoteProcessGroupStatusDto(remoteProcessGroup, remoteProcessGroupStatus)
2144             );
2145             final List<BulletinDTO> bulletins = createBulletinDtos(bulletinRepository.findBulletinsForSource(remoteProcessGroup.getIdentifier()));
2146             final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
2147             flow.getRemoteProcessGroups().add(entityFactory.createRemoteProcessGroupEntity(dto, revision, permissions, operatePermissions, status, bulletinEntities));
2148         }
2149
2150         return flow;
2151     }
2152
2153     private <T, S> T getComponentStatus(final Supplier<S> getComponentStatus, final Function<S, T> convertToDto) {
2154         final T statusDTO;
2155         final S status = getComponentStatus.get();
2156         if (status != null) {
2157             statusDTO = convertToDto.apply(status);
2158         } else {
2159             statusDTO = null;
2160         }
2161         return statusDTO;
2162     }
2163
2164     public FlowDTO createFlowDto(final ProcessGroup group, final ProcessGroupStatus groupStatus, final RevisionManager revisionManager,
2165                                  final Function<ProcessGroup, List<BulletinEntity>> getProcessGroupBulletins) {
2166         final FlowDTO dto = new FlowDTO();
2167
2168         for (final ProcessorNode procNode : group.getProcessors()) {
2169             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(procNode.getIdentifier()));
2170             final PermissionsDTO permissions = createPermissionsDto(procNode);
2171             final PermissionsDTO operatePermissions = createPermissionsDto(new OperationAuthorizable(procNode));
2172             final ProcessorStatusDTO status = getComponentStatus(
2173                 () -> groupStatus.getProcessorStatus().stream().filter(processorStatus -> procNode.getIdentifier().equals(processorStatus.getId())).findFirst().orElse(null),
2174                 processorStatus -> createProcessorStatusDto(processorStatus)
2175             );
2176             final List<BulletinDTO> bulletins = createBulletinDtos(bulletinRepository.findBulletinsForSource(procNode.getIdentifier()));
2177             final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
2178             dto.getProcessors().add(entityFactory.createProcessorEntity(createProcessorDto(procNode), revision, permissions, operatePermissions, status, bulletinEntities));
2179         }
2180
2181         for (final Connection connNode : group.getConnections()) {
2182             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(connNode.getIdentifier()));
2183             final PermissionsDTO permissions = createPermissionsDto(connNode);
2184             final ConnectionStatusDTO status = getComponentStatus(
2185                 () -> groupStatus.getConnectionStatus().stream().filter(connectionStatus -> connNode.getIdentifier().equals(connectionStatus.getId())).findFirst().orElse(null),
2186                 connectionStatus -> createConnectionStatusDto(connectionStatus)
2187             );
2188             dto.getConnections().add(entityFactory.createConnectionEntity(createConnectionDto(connNode), revision, permissions, status));
2189         }
2190
2191         for (final Label label : group.getLabels()) {
2192             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(label.getIdentifier()));
2193             final PermissionsDTO permissions = createPermissionsDto(label);
2194             dto.getLabels().add(entityFactory.createLabelEntity(createLabelDto(label), revision, permissions));
2195         }
2196
2197         for (final Funnel funnel : group.getFunnels()) {
2198             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(funnel.getIdentifier()));
2199             final PermissionsDTO permissions = createPermissionsDto(funnel);
2200             dto.getFunnels().add(entityFactory.createFunnelEntity(createFunnelDto(funnel), revision, permissions));
2201         }
2202
2203         for (final ProcessGroup childGroup : group.getProcessGroups()) {
2204             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(childGroup.getIdentifier()));
2205             final PermissionsDTO permissions = createPermissionsDto(childGroup);
2206             final ProcessGroupStatusDTO status = getComponentStatus(
2207                 () -> groupStatus.getProcessGroupStatus().stream().filter(processGroupStatus -> childGroup.getIdentifier().equals(processGroupStatus.getId())).findFirst().orElse(null),
2208                 processGroupStatus -> createConciseProcessGroupStatusDto(processGroupStatus)
2209             );
2210             final List<BulletinEntity> bulletins = getProcessGroupBulletins.apply(childGroup);
2211             dto.getProcessGroups().add(entityFactory.createProcessGroupEntity(createProcessGroupDto(childGroup), revision, permissions, status, bulletins));
2212         }
2213
2214         for (final RemoteProcessGroup rpg : group.getRemoteProcessGroups()) {
2215             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(rpg.getIdentifier()));
2216             final PermissionsDTO permissions = createPermissionsDto(rpg);
2217             final PermissionsDTO operatePermissions = createPermissionsDto(new OperationAuthorizable(rpg));
2218             final RemoteProcessGroupStatusDTO status = getComponentStatus(
2219                 () -> groupStatus.getRemoteProcessGroupStatus().stream().filter(remoteProcessGroupStatus -> rpg.getIdentifier().equals(remoteProcessGroupStatus.getId())).findFirst().orElse(null),
2220                 remoteProcessGroupStatus -> createRemoteProcessGroupStatusDto(rpg, remoteProcessGroupStatus)
2221             );
2222             final List<BulletinDTO> bulletins = createBulletinDtos(bulletinRepository.findBulletinsForSource(rpg.getIdentifier()));
2223             final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
2224             dto.getRemoteProcessGroups().add(entityFactory.createRemoteProcessGroupEntity(createRemoteProcessGroupDto(rpg), revision, permissions, operatePermissions, status, bulletinEntities));
2225         }
2226
2227         for (final Port inputPort : group.getInputPorts()) {
2228             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(inputPort.getIdentifier()));
2229             final PermissionsDTO permissions = createPermissionsDto(inputPort);
2230             final PermissionsDTO operatePermissions = createPermissionsDto(new OperationAuthorizable(inputPort));
2231             final PortStatusDTO status = getComponentStatus(
2232                 () -> groupStatus.getInputPortStatus().stream().filter(inputPortStatus -> inputPort.getIdentifier().equals(inputPortStatus.getId())).findFirst().orElse(null),
2233                 inputPortStatus -> createPortStatusDto(inputPortStatus)
2234             );
2235             final List<BulletinDTO> bulletins = createBulletinDtos(bulletinRepository.findBulletinsForSource(inputPort.getIdentifier()));
2236             final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
2237             dto.getInputPorts().add(entityFactory.createPortEntity(createPortDto(inputPort), revision, permissions, operatePermissions, status, bulletinEntities));
2238         }
2239
2240         for (final Port outputPort : group.getOutputPorts()) {
2241             final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(outputPort.getIdentifier()));
2242             final PermissionsDTO permissions = createPermissionsDto(outputPort);
2243             final PermissionsDTO operatePermissions = createPermissionsDto(new OperationAuthorizable(outputPort));
2244             final PortStatusDTO status = getComponentStatus(
2245                 () -> groupStatus.getOutputPortStatus().stream().filter(outputPortStatus -> outputPort.getIdentifier().equals(outputPortStatus.getId())).findFirst().orElse(null),
2246                 outputPortStatus -> createPortStatusDto(outputPortStatus)
2247             );
2248             final List<BulletinDTO> bulletins = createBulletinDtos(bulletinRepository.findBulletinsForSource(outputPort.getIdentifier()));
2249             final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
2250             dto.getOutputPorts().add(entityFactory.createPortEntity(createPortDto(outputPort), revision, permissions, operatePermissions, status, bulletinEntities));
2251         }
2252
2253         return dto;
2254     }
2255
2256     /**
2257      * Creates a ProcessGroupDTO from the specified ProcessGroup.
2258      *
2259      * @param group group
2260      * @param recurse recurse
2261      * @return dto
2262      */
2263     public ProcessGroupDTO createProcessGroupDto(final ProcessGroup group, final boolean recurse) {
2264         final ProcessGroupDTO dto = createConciseProcessGroupDto(group);
2265         dto.setContents(createProcessGroupContentsDto(group, recurse));
2266         return dto;
2267     }
2268
2269     /**
2270      * Creates a ProcessGroupDTO from the specified ProcessGroup.
2271      *
2272      * @param group group
2273      * @return dto
2274      */
2275     private ProcessGroupDTO createConciseProcessGroupDto(final ProcessGroup group) {
2276         if (group == null) {
2277             return null;
2278         }
2279
2280         final ProcessGroupDTO dto = new ProcessGroupDTO();
2281         dto.setId(group.getIdentifier());
2282         dto.setPosition(createPositionDto(group.getPosition()));
2283         dto.setComments(group.getComments());
2284         dto.setName(group.getName());
2285         dto.setVersionedComponentId(group.getVersionedComponentId().orElse(null));
2286         dto.setVersionControlInformation(createVersionControlInformationDto(group));
2287
2288         final Map<String, String> variables = group.getVariableRegistry().getVariableMap().entrySet().stream()
2289             .collect(Collectors.toMap(entry -> entry.getKey().getName(), entry -> entry.getValue()));
2290         dto.setVariables(variables);
2291
2292         final ProcessGroup parentGroup = group.getParent();
2293         if (parentGroup != null) {
2294             dto.setParentGroupId(parentGroup.getIdentifier());
2295         }
2296
2297         final ProcessGroupCounts counts = group.getCounts();
2298         dto.setRunningCount(counts.getRunningCount());
2299         dto.setStoppedCount(counts.getStoppedCount());
2300         dto.setInvalidCount(counts.getInvalidCount());
2301         dto.setDisabledCount(counts.getDisabledCount());
2302         dto.setInputPortCount(counts.getInputPortCount());
2303         dto.setOutputPortCount(counts.getOutputPortCount());
2304         dto.setActiveRemotePortCount(counts.getActiveRemotePortCount());
2305         dto.setInactiveRemotePortCount(counts.getInactiveRemotePortCount());
2306         dto.setUpToDateCount(counts.getUpToDateCount());
2307         dto.setLocallyModifiedCount(counts.getLocallyModifiedCount());
2308         dto.setStaleCount(counts.getStaleCount());
2309         dto.setLocallyModifiedAndStaleCount(counts.getLocallyModifiedAndStaleCount());
2310         dto.setSyncFailureCount(counts.getSyncFailureCount());
2311
2312         return dto;
2313     }
2314
2315
2316     public Set<ComponentDifferenceDTO> createComponentDifferenceDtos(final FlowComparison comparison) {
2317         final Map<ComponentDifferenceDTO, List<DifferenceDTO>> differencesByComponent = new HashMap<>();
2318
2319         for (final FlowDifference difference : comparison.getDifferences()) {
2320             // Ignore these as local differences for now because we can't do anything with it
2321             if (difference.getDifferenceType() == DifferenceType.BUNDLE_CHANGED) {
2322                 continue;
2323             }
2324
2325             // Ignore differences for adding remote ports
2326             if (FlowDifferenceFilters.isAddedOrRemovedRemotePort(difference)) {
2327                 continue;
2328             }
2329
2330             if (FlowDifferenceFilters.isIgnorableVersionedFlowCoordinateChange(difference)) {
2331                 continue;
2332             }
2333
2334             final ComponentDifferenceDTO componentDiff = createComponentDifference(difference);
2335             final List<DifferenceDTO> differences = differencesByComponent.computeIfAbsent(componentDiff, key -> new ArrayList<>());
2336
2337             final DifferenceDTO dto = new DifferenceDTO();
2338             dto.setDifferenceType(difference.getDifferenceType().getDescription());
2339             dto.setDifference(difference.getDescription());
2340
2341             differences.add(dto);
2342         }
2343
2344         for (final Map.Entry<ComponentDifferenceDTO, List<DifferenceDTO>> entry : differencesByComponent.entrySet()) {
2345             entry.getKey().setDifferences(entry.getValue());
2346         }
2347
2348         return differencesByComponent.keySet();
2349     }
2350
2351     private ComponentDifferenceDTO createComponentDifference(final FlowDifference difference) {
2352         VersionedComponent component = difference.getComponentA();
2353         if (component == null || difference.getComponentB() instanceof InstantiatedVersionedComponent) {
2354             component = difference.getComponentB();
2355         }
2356
2357         final ComponentDifferenceDTO dto = new ComponentDifferenceDTO();
2358         dto.setComponentName(component.getName());
2359         dto.setComponentType(component.getComponentType().toString());
2360
2361         if (component instanceof InstantiatedVersionedComponent) {
2362             final InstantiatedVersionedComponent instantiatedComponent = (InstantiatedVersionedComponent) component;
2363             dto.setComponentId(instantiatedComponent.getInstanceId());
2364             dto.setProcessGroupId(instantiatedComponent.getInstanceGroupId());
2365         } else {
2366             dto.setComponentId(component.getIdentifier());
2367             dto.setProcessGroupId(dto.getProcessGroupId());
2368         }
2369
2370         return dto;
2371     }
2372
2373
2374     public VersionControlInformationDTO createVersionControlInformationDto(final ProcessGroup group) {
2375         if (group == null) {
2376             return null;
2377         }
2378
2379         final VersionControlInformation versionControlInfo = group.getVersionControlInformation();
2380         if (versionControlInfo == null) {
2381             return null;
2382         }
2383
2384         final VersionControlInformationDTO dto = new VersionControlInformationDTO();
2385         dto.setGroupId(group.getIdentifier());
2386         dto.setRegistryId(versionControlInfo.getRegistryIdentifier());
2387         dto.setRegistryName(versionControlInfo.getRegistryName());
2388         dto.setBucketId(versionControlInfo.getBucketIdentifier());
2389         dto.setBucketName(versionControlInfo.getBucketName());
2390         dto.setFlowId(versionControlInfo.getFlowIdentifier());
2391         dto.setFlowName(versionControlInfo.getFlowName());
2392         dto.setFlowDescription(versionControlInfo.getFlowDescription());
2393         dto.setVersion(versionControlInfo.getVersion());
2394
2395         final VersionedFlowStatus status = versionControlInfo.getStatus();
2396         final VersionedFlowState state = status.getState();
2397         dto.setState(state == null ? null : state.name());
2398         dto.setStateExplanation(status.getStateExplanation());
2399
2400         return dto;
2401     }
2402
2403     public Map<String, String> createVersionControlComponentMappingDto(final InstantiatedVersionedProcessGroup group) {
2404         final Map<String, String> mapping = new HashMap<>();
2405
2406         mapping.put(group.getInstanceId(), group.getIdentifier());
2407         group.getProcessors().stream()
2408             .map(proc -> (InstantiatedVersionedProcessor) proc)
2409             .forEach(proc -> mapping.put(proc.getInstanceId(), proc.getIdentifier()));
2410         group.getFunnels().stream()
2411             .map(funnel -> (InstantiatedVersionedFunnel) funnel)
2412             .forEach(funnel -> mapping.put(funnel.getInstanceId(), funnel.getIdentifier()));
2413         group.getInputPorts().stream()
2414             .map(port -> (InstantiatedVersionedPort) port)
2415             .forEach(port -> mapping.put(port.getInstanceId(), port.getIdentifier()));
2416         group.getOutputPorts().stream()
2417             .map(port -> (InstantiatedVersionedPort) port)
2418             .forEach(port -> mapping.put(port.getInstanceId(), port.getIdentifier()));
2419         group.getControllerServices().stream()
2420             .map(service -> (InstantiatedVersionedControllerService) service)
2421             .forEach(service -> mapping.put(service.getInstanceId(), service.getIdentifier()));
2422         group.getLabels().stream()
2423             .map(label -> (InstantiatedVersionedLabel) label)
2424             .forEach(label -> mapping.put(label.getInstanceId(), label.getIdentifier()));
2425         group.getConnections().stream()
2426             .map(conn -> (InstantiatedVersionedConnection) conn)
2427             .forEach(conn -> mapping.put(conn.getInstanceId(), conn.getIdentifier()));
2428         group.getRemoteProcessGroups().stream()
2429             .map(rpg -> (InstantiatedVersionedRemoteProcessGroup) rpg)
2430             .forEach(rpg -> {
2431                 mapping.put(rpg.getInstanceId(), rpg.getIdentifier());
2432
2433                 if (rpg.getInputPorts() != null) {
2434                     rpg.getInputPorts().stream()
2435                         .map(port -> (InstantiatedVersionedRemoteGroupPort) port)
2436                         .forEach(port -> mapping.put(port.getInstanceId(), port.getIdentifier()));
2437                 }
2438
2439                 if (rpg.getOutputPorts() != null) {
2440                     rpg.getOutputPorts().stream()
2441                         .map(port -> (InstantiatedVersionedRemoteGroupPort) port)
2442                         .forEach(port -> mapping.put(port.getInstanceId(), port.getIdentifier()));
2443                 }
2444             });
2445
2446         group.getProcessGroups().stream()
2447             .map(child -> (InstantiatedVersionedProcessGroup) child)
2448             .forEach(child -> {
2449                 final Map<String, String> childMapping = createVersionControlComponentMappingDto(child);
2450                 mapping.putAll(childMapping);
2451             });
2452
2453         return mapping;
2454     }
2455
2456
2457     /**
2458      * Creates a ProcessGroupContentDTO from the specified ProcessGroup.
2459      *
2460      * @param group group
2461      * @param recurse recurse
2462      * @return dto
2463      */
2464     private FlowSnippetDTO createProcessGroupContentsDto(final ProcessGroup group, final boolean recurse) {
2465         if (group == null) {
2466             return null;
2467         }
2468
2469         final FlowSnippetDTO dto = new FlowSnippetDTO();
2470
2471         for (final ProcessorNode procNode : group.getProcessors()) {
2472             dto.getProcessors().add(createProcessorDto(procNode));
2473         }
2474
2475         for (final Connection connNode : group.getConnections()) {
2476             dto.getConnections().add(createConnectionDto(connNode));
2477         }
2478
2479         for (final Label label : group.getLabels()) {
2480             dto.getLabels().add(createLabelDto(label));
2481         }
2482
2483         for (final Funnel funnel : group.getFunnels()) {
2484             dto.getFunnels().add(createFunnelDto(funnel));
2485         }
2486
2487         for (final ProcessGroup childGroup : group.getProcessGroups()) {
2488             if (recurse) {
2489                 dto.getProcessGroups().add(createProcessGroupDto(childGroup, recurse));
2490             } else {
2491                 dto.getProcessGroups().add(createConciseProcessGroupDto(childGroup));
2492             }
2493         }
2494
2495         for (final RemoteProcessGroup remoteProcessGroup : group.getRemoteProcessGroups()) {
2496             dto.getRemoteProcessGroups().add(createRemoteProcessGroupDto(remoteProcessGroup));
2497         }
2498
2499         for (final Port inputPort : group.getInputPorts()) {
2500             dto.getInputPorts().add(createPortDto(inputPort));
2501         }
2502
2503         for (final Port outputPort : group.getOutputPorts()) {
2504             dto.getOutputPorts().add(createPortDto(outputPort));
2505         }
2506
2507         return dto;
2508     }
2509
2510     private boolean isRestricted(final Class<?> cls) {
2511         return cls.isAnnotationPresent(Restricted.class);
2512     }
2513
2514     private String getUsageRestriction(final Class<?> cls) {
2515         final Restricted restricted = cls.getAnnotation(Restricted.class);
2516
2517         if (restricted == null) {
2518             return null;
2519         }
2520
2521         if (StringUtils.isBlank(restricted.value())) {
2522             return null;
2523         }
2524
2525         return restricted.value();
2526     }
2527
2528     private Set<ExplicitRestrictionDTO> getExplicitRestrictions(final Class<?> cls) {
2529         final Restricted restricted = cls.getAnnotation(Restricted.class);
2530
2531         if (restricted == null) {
2532             return null;
2533         }
2534
2535         final Restriction[] restrictions = restricted.restrictions();
2536
2537         if (restrictions == null || restrictions.length == 0) {
2538             return null;
2539         }
2540
2541         return Arrays.stream(restrictions).map(restriction -> {
2542             final RequiredPermissionDTO requiredPermission = new RequiredPermissionDTO();
2543             requiredPermission.setId(restriction.requiredPermission().getPermissionIdentifier());
2544             requiredPermission.setLabel(restriction.requiredPermission().getPermissionLabel());
2545
2546             final ExplicitRestrictionDTO usageRestriction = new ExplicitRestrictionDTO();
2547             usageRestriction.setRequiredPermission(requiredPermission);
2548             usageRestriction.setExplanation(restriction.explanation());
2549             return usageRestriction;
2550         }).collect(Collectors.toSet());
2551     }
2552
2553     private String getDeprecationReason(final Class<?> cls) {
2554         final DeprecationNotice deprecationNotice = cls.getAnnotation(DeprecationNotice.class);
2555         return deprecationNotice == null ? null : deprecationNotice.reason();
2556     }
2557
2558     public Set<AffectedComponentEntity> createAffectedComponentEntities(final Set<ComponentNode> affectedComponents, final RevisionManager revisionManager) {
2559         return affectedComponents.stream()
2560                 .map(component -> {
2561                     final AffectedComponentDTO affectedComponent = createAffectedComponentDto(component);
2562                     final PermissionsDTO permissions = createPermissionsDto(component);
2563                     final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(component.getIdentifier()));
2564                     return entityFactory.createAffectedComponentEntity(affectedComponent, revision, permissions);
2565                 })
2566                 .collect(Collectors.toSet());
2567     }
2568
2569     public VariableRegistryDTO createVariableRegistryDto(final ProcessGroup processGroup, final RevisionManager revisionManager) {
2570         final ComponentVariableRegistry variableRegistry = processGroup.getVariableRegistry();
2571
2572         final List<String> variableNames = variableRegistry.getVariableMap().keySet().stream()
2573             .map(descriptor -> descriptor.getName())
2574             .collect(Collectors.toList());
2575
2576         final Set<VariableEntity> variableEntities = new LinkedHashSet<>();
2577
2578         for (final String variableName : variableNames) {
2579             final VariableDTO variableDto = new VariableDTO();
2580             variableDto.setName(variableName);
2581             variableDto.setValue(variableRegistry.getVariableValue(variableName));
2582             variableDto.setProcessGroupId(processGroup.getIdentifier());
2583
2584             final Set<AffectedComponentEntity> affectedComponentEntities = createAffectedComponentEntities(processGroup.getComponentsAffectedByVariable(variableName), revisionManager);
2585
2586             boolean canWrite = true;
2587             for (final AffectedComponentEntity affectedComponent : affectedComponentEntities) {
2588                 final PermissionsDTO permissions = affectedComponent.getPermissions();
2589                 if (!permissions.getCanRead() || !permissions.getCanWrite()) {
2590                     canWrite = false;
2591                     break;
2592                 }
2593             }
2594
2595             variableDto.setAffectedComponents(affectedComponentEntities);
2596
2597             final VariableEntity variableEntity = new VariableEntity();
2598             variableEntity.setVariable(variableDto);
2599             variableEntity.setCanWrite(canWrite);
2600
2601             variableEntities.add(variableEntity);
2602         }
2603
2604         final VariableRegistryDTO registryDto = new VariableRegistryDTO();
2605         registryDto.setProcessGroupId(processGroup.getIdentifier());
2606         registryDto.setVariables(variableEntities);
2607
2608         return registryDto;
2609     }
2610
2611     public VariableRegistryUpdateRequestDTO createVariableRegistryUpdateRequestDto(final VariableRegistryUpdateRequest request) {
2612         final VariableRegistryUpdateRequestDTO dto = new VariableRegistryUpdateRequestDTO();
2613         dto.setComplete(request.isComplete());
2614         dto.setFailureReason(request.getFailureReason());
2615         dto.setLastUpdated(request.getLastUpdated());
2616         dto.setProcessGroupId(request.getProcessGroupId());
2617         dto.setRequestId(request.getRequestId());
2618         dto.setSubmissionTime(request.getSubmissionTime());
2619
2620         final List<VariableRegistryUpdateStepDTO> updateSteps = new ArrayList<>();
2621         updateSteps.add(createVariableRegistryUpdateStepDto(request.getIdentifyRelevantComponentsStep()));
2622         updateSteps.add(createVariableRegistryUpdateStepDto(request.getStopProcessorsStep()));
2623         updateSteps.add(createVariableRegistryUpdateStepDto(request.getDisableServicesStep()));
2624         updateSteps.add(createVariableRegistryUpdateStepDto(request.getApplyUpdatesStep()));
2625         updateSteps.add(createVariableRegistryUpdateStepDto(request.getEnableServicesStep()));
2626         updateSteps.add(createVariableRegistryUpdateStepDto(request.getStartProcessorsStep()));
2627         dto.setUpdateSteps(updateSteps);
2628
2629         dto.setAffectedComponents(new HashSet<>(request.getAffectedComponents().values()));
2630
2631         return dto;
2632     }
2633
2634     public VariableRegistryUpdateStepDTO createVariableRegistryUpdateStepDto(final VariableRegistryUpdateStep step) {
2635         final VariableRegistryUpdateStepDTO dto = new VariableRegistryUpdateStepDTO();
2636         dto.setComplete(step.isComplete());
2637         dto.setDescription(step.getDescription());
2638         dto.setFailureReason(step.getFailureReason());
2639         return dto;
2640     }
2641
2642
2643     public VariableRegistryDTO populateAffectedComponents(final VariableRegistryDTO variableRegistry, final ProcessGroup group, final RevisionManager revisionManager) {
2644         if (!group.getIdentifier().equals(variableRegistry.getProcessGroupId())) {
2645             throw new IllegalArgumentException("Variable Registry does not have the same Group ID as the given Process Group");
2646         }
2647
2648         final Set<VariableEntity> variableEntities = new LinkedHashSet<>();
2649
2650         if (variableRegistry.getVariables() != null) {
2651             for (final VariableEntity inputEntity : variableRegistry.getVariables()) {
2652                 final VariableEntity entity = new VariableEntity();
2653
2654                 final VariableDTO inputDto = inputEntity.getVariable();
2655                 final VariableDTO variableDto = new VariableDTO();
2656                 variableDto.setName(inputDto.getName());
2657                 variableDto.setValue(inputDto.getValue());
2658                 variableDto.setProcessGroupId(group.getIdentifier());
2659
2660                 final Set<AffectedComponentEntity> affectedComponentEntities = createAffectedComponentEntities(group.getComponentsAffectedByVariable(variableDto.getName()), revisionManager);
2661
2662                 boolean canWrite = true;
2663                 for (final AffectedComponentEntity affectedComponent : affectedComponentEntities) {
2664                     final PermissionsDTO permissions = affectedComponent.getPermissions();
2665                     if (!permissions.getCanRead() || !permissions.getCanWrite()) {
2666                         canWrite = false;
2667                         break;
2668                     }
2669                 }
2670
2671                 variableDto.setAffectedComponents(affectedComponentEntities);
2672
2673                 entity.setCanWrite(canWrite);
2674                 entity.setVariable(inputDto);
2675
2676                 variableEntities.add(entity);
2677             }
2678         }
2679
2680         final VariableRegistryDTO registryDto = new VariableRegistryDTO();
2681         registryDto.setProcessGroupId(group.getIdentifier());
2682         registryDto.setVariables(variableEntities);
2683
2684         return registryDto;
2685     }
2686
2687
2688     /**
2689      * Gets the capability description from the specified class.
2690      */
2691     private String getCapabilityDescription(final Class<?> cls) {
2692         final CapabilityDescription capabilityDesc = cls.getAnnotation(CapabilityDescription.class);
2693         return capabilityDesc == null ? null : capabilityDesc.value();
2694     }
2695
2696     /**
2697      * Gets the tags from the specified class.
2698      */
2699     private Set<String> getTags(final Class<?> cls) {
2700         final Set<String> tags = new HashSet<>();
2701         final Tags tagsAnnotation = cls.getAnnotation(Tags.class);
2702         if (tagsAnnotation != null) {
2703             for (final String tag : tagsAnnotation.value()) {
2704                 tags.add(tag);
2705             }
2706         }
2707
2708         if (cls.isAnnotationPresent(Restricted.class)) {
2709             tags.add("restricted");
2710         }
2711
2712         return tags;
2713     }
2714
2715     /**
2716      * Creates a bundle DTO from the specified class.
2717      *
2718      * @param coordinate bundle coordinates
2719      * @return dto
2720      */
2721     public BundleDTO createBundleDto(final BundleCoordinate coordinate) {
2722         final BundleDTO dto = new BundleDTO();
2723         dto.setGroup(coordinate.getGroup());
2724         dto.setArtifact(coordinate.getId());
2725         dto.setVersion(coordinate.getVersion());
2726         return dto;
2727     }
2728
2729     private List<ControllerServiceApiDTO> createControllerServiceApiDto(final Class cls) {
2730         final Set<Class> serviceApis = new HashSet<>();
2731
2732         // if this is a controller service
2733         if (ControllerService.class.isAssignableFrom(cls)) {
2734             // get all of it's interfaces to determine the controller service api's it implements
2735             final List<Class<?>> interfaces = ClassUtils.getAllInterfaces(cls);
2736             for (final Class i : interfaces) {
2737                 // add all controller services that's not ControllerService itself
2738                 if (ControllerService.class.isAssignableFrom(i) && !ControllerService.class.equals(i)) {
2739                     serviceApis.add(i);
2740                 }
2741             }
2742
2743             final List<ControllerServiceApiDTO> dtos = new ArrayList<>();
2744             for (final Class serviceApi : serviceApis) {
2745                 final Bundle bundle = extensionManager.getBundle(serviceApi.getClassLoader());
2746                 final BundleCoordinate bundleCoordinate = bundle.getBundleDetails().getCoordinate();
2747
2748                 final ControllerServiceApiDTO dto = new ControllerServiceApiDTO();
2749                 dto.setType(serviceApi.getName());
2750                 dto.setBundle(createBundleDto(bundleCoordinate));
2751                 dtos.add(dto);
2752             }
2753             return dtos;
2754         } else {
2755             return null;
2756         }
2757     }
2758
2759     /**
2760      * Gets the DocumentedTypeDTOs from the specified classes.
2761      *
2762      * @param classes classes
2763      * @param bundleGroupFilter if specified, must be member of bundle group
2764      * @param bundleArtifactFilter if specified, must be member of bundle artifact
2765      * @param typeFilter if specified, type must match
2766      * @return dtos
2767      */
2768     public Set<DocumentedTypeDTO> fromDocumentedTypes(final Map<Class, Bundle> classes, final String bundleGroupFilter, final String bundleArtifactFilter, final String typeFilter) {
2769         final Set<DocumentedTypeDTO> types = new LinkedHashSet<>();
2770         final List<Class> sortedClasses = new ArrayList<>(classes.keySet());
2771         Collections.sort(sortedClasses, CLASS_NAME_COMPARATOR);
2772
2773         for (final Class cls : sortedClasses) {
2774             final Bundle bundle = classes.get(cls);
2775             final BundleCoordinate coordinate = bundle.getBundleDetails().getCoordinate();
2776
2777             // only include classes that meet the criteria if specified
2778             if (bundleGroupFilter != null && !bundleGroupFilter.equals(coordinate.getGroup())) {
2779                 continue;
2780             }
2781             if (bundleArtifactFilter != null && !bundleArtifactFilter.equals(coordinate.getId())) {
2782                 continue;
2783             }
2784             if (typeFilter != null && !typeFilter.equals(cls.getName())) {
2785                 continue;
2786             }
2787
2788             final DocumentedTypeDTO dto = new DocumentedTypeDTO();
2789             dto.setType(cls.getName());
2790             dto.setBundle(createBundleDto(coordinate));
2791             dto.setControllerServiceApis(createControllerServiceApiDto(cls));
2792             dto.setDescription(getCapabilityDescription(cls));
2793             dto.setRestricted(isRestricted(cls));
2794             dto.setUsageRestriction(getUsageRestriction(cls));
2795             dto.setExplicitRestrictions(getExplicitRestrictions(cls));
2796             dto.setDeprecationReason(getDeprecationReason(cls));
2797             dto.setTags(getTags(cls));
2798             types.add(dto);
2799         }
2800
2801         return types;
2802     }
2803
2804     /**
2805      * Gets the DocumentedTypeDTOs from the specified classes.
2806      *
2807      * @param classes classes
2808      * @param bundleGroupFilter if specified, must be member of bundle group
2809      * @param bundleArtifactFilter if specified, must be member of bundle artifact
2810      * @param typeFilter if specified, type must match
2811      * @return dtos
2812      */
2813     public Set<DocumentedTypeDTO> fromDocumentedTypes(final Set<Class> classes, final String bundleGroupFilter, final String bundleArtifactFilter, final String typeFilter) {
2814         final Map<Class, Bundle> classBundles = new HashMap<>();
2815         for (final Class cls : classes) {
2816             classBundles.put(cls, extensionManager.getBundle(cls.getClassLoader()));
2817         }
2818         return fromDocumentedTypes(classBundles, bundleGroupFilter, bundleArtifactFilter, typeFilter);
2819     }
2820
2821     /**
2822      * Creates a ProcessorDTO from the specified ProcessorNode.
2823      *
2824      * @param node node
2825      * @return dto
2826      */
2827     public ProcessorDTO createProcessorDto(final ProcessorNode node) {
2828         if (node == null) {
2829             return null;
2830         }
2831
2832         final BundleCoordinate bundleCoordinate = node.getBundleCoordinate();
2833         final List<Bundle> compatibleBundles = extensionManager.getBundles(node.getCanonicalClassName()).stream().filter(bundle -> {
2834             final BundleCoordinate coordinate = bundle.getBundleDetails().getCoordinate();
2835             return bundleCoordinate.getGroup().equals(coordinate.getGroup()) && bundleCoordinate.getId().equals(coordinate.getId());
2836         }).collect(Collectors.toList());
2837
2838         final ProcessorDTO dto = new ProcessorDTO();
2839         dto.setId(node.getIdentifier());
2840         dto.setPosition(createPositionDto(node.getPosition()));
2841         dto.setStyle(node.getStyle());
2842         dto.setParentGroupId(node.getProcessGroup().getIdentifier());
2843         dto.setInputRequirement(node.getInputRequirement().name());
2844         dto.setPersistsState(node.getProcessor().getClass().isAnnotationPresent(Stateful.class));
2845         dto.setRestricted(node.isRestricted());
2846         dto.setDeprecated(node.isDeprecated());
2847         dto.setExecutionNodeRestricted(node.isExecutionNodeRestricted());
2848         dto.setExtensionMissing(node.isExtensionMissing());
2849         dto.setMultipleVersionsAvailable(compatibleBundles.size() > 1);
2850         dto.setVersionedComponentId(node.getVersionedComponentId().orElse(null));
2851
2852         dto.setType(node.getCanonicalClassName());
2853         dto.setBundle(createBundleDto(bundleCoordinate));
2854         dto.setName(node.getName());
2855         dto.setState(node.getScheduledState().toString());
2856
2857         // build the relationship dtos
2858         final List<RelationshipDTO> relationships = new ArrayList<>();
2859         for (final Relationship rel : node.getRelationships()) {
2860             final RelationshipDTO relationshipDTO = new RelationshipDTO();
2861             relationshipDTO.setDescription(rel.getDescription());
2862             relationshipDTO.setName(rel.getName());
2863             relationshipDTO.setAutoTerminate(node.isAutoTerminated(rel));
2864             relationships.add(relationshipDTO);
2865         }
2866
2867         // sort the relationships
2868         Collections.sort(relationships, new Comparator<RelationshipDTO>() {
2869             @Override
2870             public int compare(final RelationshipDTO r1, final RelationshipDTO r2) {
2871                 return Collator.getInstance(Locale.US).compare(r1.getName(), r2.getName());
2872             }
2873         });
2874
2875         // set the relationships
2876         dto.setRelationships(relationships);
2877
2878         dto.setDescription(getCapabilityDescription(node.getClass()));
2879         dto.setSupportsParallelProcessing(!node.isTriggeredSerially());
2880         dto.setSupportsEventDriven(node.isEventDrivenSupported());
2881         dto.setSupportsBatching(node.isSessionBatchingSupported());
2882         dto.setConfig(createProcessorConfigDto(node));
2883
2884         final ValidationStatus validationStatus = node.getValidationStatus(1, TimeUnit.MILLISECONDS);
2885         dto.setValidationStatus(validationStatus.name());
2886
2887         final Collection<ValidationResult> validationErrors = node.getValidationErrors();
2888         if (validationErrors != null && !validationErrors.isEmpty()) {
2889             final List<String> errors = new ArrayList<>();
2890             for (final ValidationResult validationResult : validationErrors) {
2891                 errors.add(validationResult.toString());
2892             }
2893
2894             dto.setValidationErrors(errors);
2895         }
2896
2897         return dto;
2898     }
2899
2900     /**
2901      * Creates a BulletinBoardDTO for the specified bulletins.
2902      *
2903      * @param bulletins bulletins
2904      * @return dto
2905      */
2906     public BulletinBoardDTO createBulletinBoardDto(final List<BulletinEntity> bulletins) {
2907         // sort the bulletins
2908         Collections.sort(bulletins, new Comparator<BulletinEntity>() {
2909             @Override
2910             public int compare(final BulletinEntity bulletin1, final BulletinEntity bulletin2) {
2911                 if (bulletin1 == null && bulletin2 == null) {
2912                     return 0;
2913                 } else if (bulletin1 == null) {
2914                     return 1;
2915                 } else if (bulletin2 == null) {
2916                     return -1;
2917                 }
2918
2919                 final Date timestamp1 = bulletin1.getTimestamp();
2920                 final Date timestamp2 = bulletin2.getTimestamp();
2921                 if (timestamp1 == null && timestamp2 == null) {
2922                     return 0;
2923                 } else if (timestamp1 == null) {
2924                     return 1;
2925                 } else if (timestamp2 == null) {
2926                     return -1;
2927                 } else {
2928                     return timestamp1.compareTo(timestamp2);
2929                 }
2930             }
2931         });
2932
2933         // create the bulletin board
2934         final BulletinBoardDTO bulletinBoard = new BulletinBoardDTO();
2935         bulletinBoard.setBulletins(bulletins);
2936         bulletinBoard.setGenerated(new Date());
2937         return bulletinBoard;
2938     }
2939
2940     /**
2941      * Creates BulletinDTOs for the specified Bulletins.
2942      *
2943      * @param bulletins bulletin
2944      * @return dto
2945      */
2946     public List<BulletinDTO> createBulletinDtos(final List<Bulletin> bulletins) {
2947         final List<BulletinDTO> bulletinDtos = new ArrayList<>(bulletins.size());
2948         for (final Bulletin bulletin : bulletins) {
2949             bulletinDtos.add(createBulletinDto(bulletin));
2950         }
2951         return bulletinDtos;
2952     }
2953
2954     /**
2955      * Creates a BulletinDTO for the specified Bulletin.
2956      *
2957      * @param bulletin bulletin
2958      * @return dto
2959      */
2960     public BulletinDTO createBulletinDto(final Bulletin bulletin) {
2961         final BulletinDTO dto = new BulletinDTO();
2962         dto.setId(bulletin.getId());
2963         dto.setNodeAddress(bulletin.getNodeAddress());
2964         dto.setTimestamp(bulletin.getTimestamp());
2965         dto.setGroupId(bulletin.getGroupId());
2966         dto.setSourceId(bulletin.getSourceId());
2967         dto.setSourceName(bulletin.getSourceName());
2968         dto.setCategory(bulletin.getCategory());
2969         dto.setLevel(bulletin.getLevel());
2970         dto.setMessage(bulletin.getMessage());
2971         return dto;
2972     }
2973
2974     /**
2975      * Creates a ProvenanceEventNodeDTO for the specified ProvenanceEventLineageNode.
2976      *
2977      * @param node node
2978      * @return dto
2979      */
2980     public ProvenanceNodeDTO createProvenanceEventNodeDTO(final ProvenanceEventLineageNode node) {
2981         final ProvenanceNodeDTO dto = new ProvenanceNodeDTO();
2982         dto.setId(node.getIdentifier());
2983         dto.setType("EVENT");
2984         dto.setEventType(node.getEventType().toString());
2985         dto.setTimestamp(new Date(node.getTimestamp()));
2986         dto.setMillis(node.getTimestamp());
2987         dto.setFlowFileUuid(node.getFlowFileUuid());
2988         dto.setParentUuids(node.getParentUuids());
2989         dto.setChildUuids(node.getChildUuids());
2990         return dto;
2991     }
2992
2993     /**
2994      * Creates a FlowFileNodeDTO for the specified LineageNode.
2995      *
2996      * @param node node
2997      * @return dto
2998      */
2999     public ProvenanceNodeDTO createFlowFileNodeDTO(final LineageNode node) {
3000         final ProvenanceNodeDTO dto = new ProvenanceNodeDTO();
3001         dto.setId(node.getIdentifier());
3002         dto.setType("FLOWFILE");
3003         dto.setTimestamp(new Date(node.getTimestamp()));
3004         dto.setMillis(node.getTimestamp());
3005         dto.setFlowFileUuid(node.getFlowFileUuid());
3006         return dto;
3007     }
3008
3009     /**
3010      * Creates a ProvenanceLinkDTO for the specified LineageEdge.
3011      *
3012      * @param edge edge
3013      * @return dto
3014      */
3015     public ProvenanceLinkDTO createProvenanceLinkDTO(final LineageEdge edge) {
3016         final LineageNode source = edge.getSource();
3017         final LineageNode target = edge.getDestination();
3018
3019         final ProvenanceLinkDTO dto = new ProvenanceLinkDTO();
3020         dto.setTimestamp(new Date(target.getTimestamp()));
3021         dto.setMillis(target.getTimestamp());
3022         dto.setFlowFileUuid(edge.getUuid());
3023         dto.setSourceId(source.getIdentifier());
3024         dto.setTargetId(target.getIdentifier());
3025         return dto;
3026     }
3027
3028     /**
3029      * Creates a LineageDTO for the specified Lineage.
3030      *
3031      * @param computeLineageSubmission submission
3032      * @return dto
3033      */
3034     public LineageDTO createLineageDto(final ComputeLineageSubmission computeLineageSubmission) {
3035         // build the lineage dto
3036         final LineageDTO dto = new LineageDTO();
3037         final LineageRequestDTO requestDto = new LineageRequestDTO();
3038         final LineageResultsDTO resultsDto = new LineageResultsDTO();
3039
3040         // include the original request and results
3041         dto.setRequest(requestDto);
3042         dto.setResults(resultsDto);
3043
3044         // rebuild the request from the submission object
3045         switch (computeLineageSubmission.getLineageComputationType()) {
3046             case EXPAND_CHILDREN:
3047                 requestDto.setEventId(computeLineageSubmission.getExpandedEventId());
3048                 requestDto.setLineageRequestType(LineageRequestType.CHILDREN);
3049                 break;
3050             case EXPAND_PARENTS:
3051                 requestDto.setEventId(computeLineageSubmission.getExpandedEventId());
3052                 requestDto.setLineageRequestType(LineageRequestType.PARENTS);
3053                 break;
3054             case FLOWFILE_LINEAGE:
3055                 final Collection<String> uuids = computeLineageSubmission.getLineageFlowFileUuids();
3056                 if (uuids.size() == 1) {
3057                     requestDto.setUuid(uuids.iterator().next());
3058                 }
3059                 requestDto.setEventId(computeLineageSubmission.getExpandedEventId());
3060                 requestDto.setLineageRequestType(LineageRequestType.FLOWFILE);
3061                 break;
3062         }
3063
3064         // include lineage details
3065         dto.setId(computeLineageSubmission.getLineageIdentifier());
3066         dto.setSubmissionTime(computeLineageSubmission.getSubmissionTime());
3067
3068         // create the results dto
3069         final ComputeLineageResult results = computeLineageSubmission.getResult();
3070         dto.setFinished(results.isFinished());
3071         dto.setPercentCompleted(results.getPercentComplete());
3072         dto.setExpiration(results.getExpiration());
3073
3074         final List<LineageNode> nodes = results.getNodes();
3075         final List<LineageEdge> edges = results.getEdges();
3076
3077         final List<ProvenanceNodeDTO> nodeDtos = new ArrayList<>();
3078         if (results.isFinished()) {
3079             // create the node dto's
3080             for (final LineageNode node : nodes) {
3081                 switch (node.getNodeType()) {
3082                     case FLOWFILE_NODE:
3083                         nodeDtos.add(createFlowFileNodeDTO(node));
3084                         break;
3085                     case PROVENANCE_EVENT_NODE:
3086                         nodeDtos.add(createProvenanceEventNodeDTO((ProvenanceEventLineageNode) node));
3087                         break;
3088                 }
3089             }
3090         }
3091         resultsDto.setNodes(nodeDtos);
3092
3093         // include any errors
3094         if (results.getError() != null) {
3095             final Set<String> errors = new HashSet<>();
3096             errors.add(results.getError());
3097             resultsDto.setErrors(errors);
3098         }
3099
3100         // create the link dto's
3101         final List<ProvenanceLinkDTO> linkDtos = new ArrayList<>();
3102         for (final LineageEdge edge : edges) {
3103             linkDtos.add(createProvenanceLinkDTO(edge));
3104         }
3105         resultsDto.setLinks(linkDtos);
3106
3107         return dto;
3108     }
3109
3110     /**
3111      * Creates a SystemDiagnosticsDTO for the specified SystemDiagnostics.
3112      *
3113      * @param sysDiagnostics diags
3114      * @return dto
3115      */
3116     public SystemDiagnosticsDTO createSystemDiagnosticsDto(final SystemDiagnostics sysDiagnostics) {
3117
3118         final SystemDiagnosticsDTO dto = new SystemDiagnosticsDTO();
3119         final SystemDiagnosticsSnapshotDTO snapshot = new SystemDiagnosticsSnapshotDTO();
3120         dto.setAggregateSnapshot(snapshot);
3121
3122         snapshot.setStatsLastRefreshed(new Date(sysDiagnostics.getCreationTimestamp()));
3123
3124         // processors
3125         snapshot.setAvailableProcessors(sysDiagnostics.getAvailableProcessors());
3126         snapshot.setProcessorLoadAverage(sysDiagnostics.getProcessorLoadAverage());
3127
3128         // threads
3129         snapshot.setDaemonThreads(sysDiagnostics.getDaemonThreads());
3130         snapshot.setTotalThreads(sysDiagnostics.getTotalThreads());
3131
3132         // heap
3133         snapshot.setMaxHeap(FormatUtils.formatDataSize(sysDiagnostics.getMaxHeap()));
3134         snapshot.setMaxHeapBytes(sysDiagnostics.getMaxHeap());
3135         snapshot.setTotalHeap(FormatUtils.formatDataSize(sysDiagnostics.getTotalHeap()));
3136         snapshot.setTotalHeapBytes(sysDiagnostics.getTotalHeap());
3137         snapshot.setUsedHeap(FormatUtils.formatDataSize(sysDiagnostics.getUsedHeap()));
3138         snapshot.setUsedHeapBytes(sysDiagnostics.getUsedHeap());
3139         snapshot.setFreeHeap(FormatUtils.formatDataSize(sysDiagnostics.getFreeHeap()));
3140         snapshot.setFreeHeapBytes(sysDiagnostics.getFreeHeap());
3141         if (sysDiagnostics.getHeapUtilization() != -1) {
3142             snapshot.setHeapUtilization(FormatUtils.formatUtilization(sysDiagnostics.getHeapUtilization()));
3143         }
3144
3145         // non heap
3146         snapshot.setMaxNonHeap(FormatUtils.formatDataSize(sysDiagnostics.getMaxNonHeap()));
3147         snapshot.setMaxNonHeapBytes(sysDiagnostics.getMaxNonHeap());
3148         snapshot.setTotalNonHeap(FormatUtils.formatDataSize(sysDiagnostics.getTotalNonHeap()));
3149         snapshot.setTotalNonHeapBytes(sysDiagnostics.getTotalNonHeap());
3150         snapshot.setUsedNonHeap(FormatUtils.formatDataSize(sysDiagnostics.getUsedNonHeap()));
3151         snapshot.setUsedNonHeapBytes(sysDiagnostics.getUsedNonHeap());
3152         snapshot.setFreeNonHeap(FormatUtils.formatDataSize(sysDiagnostics.getFreeNonHeap()));
3153         snapshot.setFreeNonHeapBytes(sysDiagnostics.getFreeNonHeap());
3154         if (sysDiagnostics.getNonHeapUtilization() != -1) {
3155             snapshot.setNonHeapUtilization(FormatUtils.formatUtilization(sysDiagnostics.getNonHeapUtilization()));
3156         }
3157
3158         // flow file disk usage
3159         final SystemDiagnosticsSnapshotDTO.StorageUsageDTO flowFileRepositoryStorageUsageDto = createStorageUsageDTO(null, sysDiagnostics.getFlowFileRepositoryStorageUsage());
3160         snapshot.setFlowFileRepositoryStorageUsage(flowFileRepositoryStorageUsageDto);
3161
3162         // content disk usage
3163         final Set<SystemDiagnosticsSnapshotDTO.StorageUsageDTO> contentRepositoryStorageUsageDtos = new LinkedHashSet<>();
3164         snapshot.setContentRepositoryStorageUsage(contentRepositoryStorageUsageDtos);
3165         for (final Map.Entry<String, StorageUsage> entry : sysDiagnostics.getContentRepositoryStorageUsage().entrySet()) {
3166             contentRepositoryStorageUsageDtos.add(createStorageUsageDTO(entry.getKey(), entry.getValue()));
3167         }
3168
3169         // provenance disk usage
3170         final Set<SystemDiagnosticsSnapshotDTO.StorageUsageDTO> provenanceRepositoryStorageUsageDtos = new LinkedHashSet<>();
3171         snapshot.setProvenanceRepositoryStorageUsage(provenanceRepositoryStorageUsageDtos);
3172         for (final Map.Entry<String, StorageUsage> entry : sysDiagnostics.getProvenanceRepositoryStorageUsage().entrySet()) {
3173             provenanceRepositoryStorageUsageDtos.add(createStorageUsageDTO(entry.getKey(), entry.getValue()));
3174         }
3175
3176         // garbage collection
3177         final Set<SystemDiagnosticsSnapshotDTO.GarbageCollectionDTO> garbageCollectionDtos = new LinkedHashSet<>();
3178         snapshot.setGarbageCollection(garbageCollectionDtos);
3179         for (final Map.Entry<String, GarbageCollection> entry : sysDiagnostics.getGarbageCollection().entrySet()) {
3180             garbageCollectionDtos.add(createGarbageCollectionDTO(entry.getKey(), entry.getValue()));
3181         }
3182
3183         // version info
3184         final SystemDiagnosticsSnapshotDTO.VersionInfoDTO versionInfoDto = createVersionInfoDTO();
3185         snapshot.setVersionInfo(versionInfoDto);
3186
3187         // uptime
3188         snapshot.setUptime(FormatUtils.formatHoursMinutesSeconds(sysDiagnostics.getUptime(), TimeUnit.MILLISECONDS));
3189
3190         return dto;
3191     }
3192
3193     /**
3194      * Creates a StorageUsageDTO from the specified StorageUsage.
3195      *
3196      * @param identifier id
3197      * @param storageUsage usage
3198      * @return dto
3199      */
3200     public SystemDiagnosticsSnapshotDTO.StorageUsageDTO createStorageUsageDTO(final String identifier, final StorageUsage storageUsage) {
3201         final SystemDiagnosticsSnapshotDTO.StorageUsageDTO dto = new SystemDiagnosticsSnapshotDTO.StorageUsageDTO();
3202         dto.setIdentifier(identifier);
3203         dto.setFreeSpace(FormatUtils.formatDataSize(storageUsage.getFreeSpace()));
3204         dto.setTotalSpace(FormatUtils.formatDataSize(storageUsage.getTotalSpace()));
3205         dto.setUsedSpace(FormatUtils.formatDataSize(storageUsage.getUsedSpace()));
3206         dto.setFreeSpaceBytes(storageUsage.getFreeSpace());
3207         dto.setTotalSpaceBytes(storageUsage.getTotalSpace());
3208         dto.setUsedSpaceBytes(storageUsage.getUsedSpace());
3209         dto.setUtilization(FormatUtils.formatUtilization(storageUsage.getDiskUtilization()));
3210         return dto;
3211     }
3212
3213     /**
3214      * Creates a GarbageCollectionDTO from the specified GarbageCollection.
3215      *
3216      * @param name name
3217      * @param garbageCollection gc
3218      * @return dto
3219      */
3220     public SystemDiagnosticsSnapshotDTO.GarbageCollectionDTO createGarbageCollectionDTO(final String name, final GarbageCollection garbageCollection) {
3221         final SystemDiagnosticsSnapshotDTO.GarbageCollectionDTO dto = new SystemDiagnosticsSnapshotDTO.GarbageCollectionDTO();
3222         dto.setName(name);
3223         dto.setCollectionCount(garbageCollection.getCollectionCount());
3224         dto.setCollectionTime(FormatUtils.formatHoursMinutesSeconds(garbageCollection.getCollectionTime(), TimeUnit.MILLISECONDS));
3225         dto.setCollectionMillis(garbageCollection.getCollectionTime());
3226         return dto;
3227     }
3228
3229     public SystemDiagnosticsSnapshotDTO.VersionInfoDTO createVersionInfoDTO() {
3230         final SystemDiagnosticsSnapshotDTO.VersionInfoDTO dto = new SystemDiagnosticsSnapshotDTO.VersionInfoDTO();
3231         dto.setJavaVendor(System.getProperty("java.vendor"));
3232         dto.setJavaVersion(System.getProperty("java.version"));
3233         dto.setOsName(System.getProperty("os.name"));
3234         dto.setOsVersion(System.getProperty("os.version"));
3235         dto.setOsArchitecture(System.getProperty("os.arch"));
3236
3237         final Bundle frameworkBundle = NarClassLoadersHolder.getInstance().getFrameworkBundle();
3238         if (frameworkBundle != null) {
3239             final BundleDetails frameworkDetails = frameworkBundle.getBundleDetails();
3240
3241             dto.setNiFiVersion(frameworkDetails.getCoordinate().getVersion());
3242
3243             // Get build info
3244             dto.setBuildTag(frameworkDetails.getBuildTag());
3245             dto.setBuildRevision(frameworkDetails.getBuildRevision());
3246             dto.setBuildBranch(frameworkDetails.getBuildBranch());
3247             dto.setBuildTimestamp(frameworkDetails.getBuildTimestampDate());
3248         }
3249
3250         return dto;
3251     }
3252
3253     /**
3254      * Creates a ResourceDTO from the specified Resource.
3255      *
3256      * @param resource resource
3257      * @return dto
3258      */
3259     public ResourceDTO createResourceDto(final Resource resource) {
3260         final ResourceDTO dto = new ResourceDTO();
3261         dto.setIdentifier(resource.getIdentifier());
3262         dto.setName(resource.getName());
3263         return dto;
3264     }
3265
3266     /**
3267      * Creates a ProcessorDiagnosticsDTO from the given Processor and status information with some additional supporting information
3268      *
3269      * @param procNode the processor to create diagnostics for
3270      * @param procStatus the status of given processor
3271      * @param bulletinRepo the bulletin repository
3272      * @param flowController flowController
3273      * @param serviceEntityFactory function for creating a ControllerServiceEntity from a given ID
3274      * @return ProcessorDiagnosticsDTO for the given Processor
3275      */
3276     public ProcessorDiagnosticsDTO createProcessorDiagnosticsDto(final ProcessorNode procNode, final ProcessorStatus procStatus, final BulletinRepository bulletinRepo,
3277             final FlowController flowController, final Function<String, ControllerServiceEntity> serviceEntityFactory) {
3278
3279         final ProcessorDiagnosticsDTO procDiagnostics = new ProcessorDiagnosticsDTO();
3280
3281         procDiagnostics.setClassLoaderDiagnostics(createClassLoaderDiagnosticsDto(procNode));
3282         procDiagnostics.setIncomingConnections(procNode.getIncomingConnections().stream()
3283             .map(this::createConnectionDiagnosticsDto)
3284             .collect(Collectors.toSet()));
3285         procDiagnostics.setOutgoingConnections(procNode.getConnections().stream()
3286             .map(this::createConnectionDiagnosticsDto)
3287             .collect(Collectors.toSet()));
3288         procDiagnostics.setJvmDiagnostics(createJvmDiagnosticsDto(flowController));
3289         procDiagnostics.setProcessor(createProcessorDto(procNode));
3290         procDiagnostics.setProcessorStatus(createProcessorStatusDto(procStatus));
3291         procDiagnostics.setThreadDumps(createThreadDumpDtos(procNode));
3292
3293         final Set<ControllerServiceDiagnosticsDTO> referencedServiceDiagnostics = createReferencedServiceDiagnostics(procNode.getProperties(),
3294             flowController.getControllerServiceProvider(), serviceEntityFactory);
3295         procDiagnostics.setReferencedControllerServices(referencedServiceDiagnostics);
3296
3297         return procDiagnostics;
3298     }
3299
3300     private Set<ControllerServiceDiagnosticsDTO> createReferencedServiceDiagnostics(final Map<PropertyDescriptor, String> properties, final ControllerServiceProvider serviceProvider,
3301         final Function<String, ControllerServiceEntity> serviceEntityFactory) {
3302
3303         final Set<ControllerServiceDiagnosticsDTO> referencedServiceDiagnostics = new HashSet<>();
3304         for (final Map.Entry<PropertyDescriptor, String> entry : properties.entrySet()) {
3305             final PropertyDescriptor descriptor = entry.getKey();
3306             if (descriptor.getControllerServiceDefinition() == null) {
3307                 continue;
3308             }
3309
3310             final String serviceId = entry.getValue();
3311             if (serviceId == null) {
3312                 continue;
3313             }
3314
3315             final ControllerServiceNode serviceNode = serviceProvider.getControllerServiceNode(serviceId);
3316             if (serviceNode == null) {
3317                 continue;
3318             }
3319
3320             final ControllerServiceDiagnosticsDTO serviceDiagnostics = createControllerServiceDiagnosticsDto(serviceNode, serviceEntityFactory, serviceProvider);
3321             if (serviceDiagnostics != null) {
3322                 referencedServiceDiagnostics.add(serviceDiagnostics);
3323             }
3324         }
3325
3326         return referencedServiceDiagnostics;
3327     }
3328
3329     /**
3330      * Creates a ControllerServiceDiagnosticsDTO from the given Controller Service with some additional supporting information
3331      *
3332      * @param serviceNode the controller service to create diagnostics for
3333      * @param serviceEntityFactory a function to convert a controller service id to a controller service entity
3334      * @param serviceProvider the controller service provider
3335      * @return ControllerServiceDiagnosticsDTO for the given Controller Service
3336      */
3337     public ControllerServiceDiagnosticsDTO createControllerServiceDiagnosticsDto(final ControllerServiceNode serviceNode, final Function<String, ControllerServiceEntity> serviceEntityFactory,
3338             final ControllerServiceProvider serviceProvider) {
3339
3340         final ControllerServiceDiagnosticsDTO serviceDiagnostics = new ControllerServiceDiagnosticsDTO();
3341         final ControllerServiceEntity serviceEntity = serviceEntityFactory.apply(serviceNode.getIdentifier());
3342         serviceDiagnostics.setControllerService(serviceEntity);
3343
3344         serviceDiagnostics.setClassLoaderDiagnostics(createClassLoaderDiagnosticsDto(serviceNode));
3345         return serviceDiagnostics;
3346     }
3347
3348
3349     private ClassLoaderDiagnosticsDTO createClassLoaderDiagnosticsDto(final ControllerServiceNode serviceNode) {
3350         ClassLoader componentClassLoader = extensionManager.getInstanceClassLoader(serviceNode.getIdentifier());
3351         if (componentClassLoader == null) {
3352             componentClassLoader = serviceNode.getControllerServiceImplementation().getClass().getClassLoader();
3353         }
3354
3355         return createClassLoaderDiagnosticsDto(componentClassLoader);
3356     }
3357
3358
3359     private ClassLoaderDiagnosticsDTO createClassLoaderDiagnosticsDto(final ProcessorNode procNode) {
3360         ClassLoader componentClassLoader = extensionManager.getInstanceClassLoader(procNode.getIdentifier());
3361         if (componentClassLoader == null) {
3362             componentClassLoader = procNode.getProcessor().getClass().getClassLoader();
3363         }
3364
3365         return createClassLoaderDiagnosticsDto(componentClassLoader);
3366     }
3367
3368     private ClassLoaderDiagnosticsDTO createClassLoaderDiagnosticsDto(final ClassLoader classLoader) {
3369         final ClassLoaderDiagnosticsDTO dto = new ClassLoaderDiagnosticsDTO();
3370
3371         final Bundle bundle = extensionManager.getBundle(classLoader);
3372         if (bundle != null) {
3373             dto.setBundle(createBundleDto(bundle.getBundleDetails().getCoordinate()));
3374         }
3375
3376         final ClassLoader parentClassLoader = classLoader.getParent();
3377         if (parentClassLoader != null) {
3378             dto.setParentClassLoader(createClassLoaderDiagnosticsDto(parentClassLoader));
3379         }
3380
3381         return dto;
3382     }
3383
3384
3385     private ConnectionDiagnosticsDTO createConnectionDiagnosticsDto(final Connection connection) {
3386         final ConnectionDiagnosticsDTO dto = new ConnectionDiagnosticsDTO();
3387         dto.setConnection(createConnectionDto(connection));
3388         dto.setAggregateSnapshot(createConnectionDiagnosticsSnapshotDto(connection));
3389         return dto;
3390     }
3391
3392     private ConnectionDiagnosticsSnapshotDTO createConnectionDiagnosticsSnapshotDto(final Connection connection) {
3393         final ConnectionDiagnosticsSnapshotDTO dto = new ConnectionDiagnosticsSnapshotDTO();
3394
3395         final QueueDiagnostics queueDiagnostics = connection.getFlowFileQueue().getQueueDiagnostics();
3396
3397         final FlowFileQueue queue = connection.getFlowFileQueue();
3398         final QueueSize totalSize = queue.size();
3399         dto.setTotalByteCount(totalSize.getByteCount());
3400         dto.setTotalFlowFileCount(totalSize.getObjectCount());
3401
3402         final LocalQueuePartitionDiagnostics localDiagnostics = queueDiagnostics.getLocalQueuePartitionDiagnostics();
3403         dto.setLocalQueuePartition(createLocalQueuePartitionDto(localDiagnostics));
3404
3405         final List<RemoteQueuePartitionDiagnostics> remoteDiagnostics = queueDiagnostics.getRemoteQueuePartitionDiagnostics();
3406         if (remoteDiagnostics != null) {
3407             final List<RemoteQueuePartitionDTO> remoteDiagnosticsDtos = remoteDiagnostics.stream()
3408                 .map(this::createRemoteQueuePartitionDto)
3409                 .collect(Collectors.toList());
3410
3411             dto.setRemoteQueuePartitions(remoteDiagnosticsDtos);
3412         }
3413
3414         return dto;
3415     }
3416
3417     private LocalQueuePartitionDTO createLocalQueuePartitionDto(final LocalQueuePartitionDiagnostics queueDiagnostics) {
3418         final LocalQueuePartitionDTO dto = new LocalQueuePartitionDTO();
3419
3420         final QueueSize activeSize = queueDiagnostics.getActiveQueueSize();
3421         dto.setActiveQueueByteCount(activeSize.getByteCount());
3422         dto.setActiveQueueFlowFileCount(activeSize.getObjectCount());
3423
3424         final QueueSize inFlightSize = queueDiagnostics.getUnacknowledgedQueueSize();
3425         dto.setInFlightByteCount(inFlightSize.getByteCount());
3426         dto.setInFlightFlowFileCount(inFlightSize.getObjectCount());
3427
3428         final QueueSize swapSize = queueDiagnostics.getSwapQueueSize();
3429         dto.setSwapByteCount(swapSize.getByteCount());
3430         dto.setSwapFlowFileCount(swapSize.getObjectCount());
3431         dto.setSwapFiles(queueDiagnostics.getSwapFileCount());
3432
3433         dto.setTotalByteCount(activeSize.getByteCount() + inFlightSize.getByteCount() + swapSize.getByteCount());
3434         dto.setTotalFlowFileCount(activeSize.getObjectCount() + inFlightSize.getObjectCount() + swapSize.getObjectCount());
3435
3436         dto.setAllActiveQueueFlowFilesPenalized(queueDiagnostics.isAllActiveFlowFilesPenalized());
3437         dto.setAnyActiveQueueFlowFilesPenalized(queueDiagnostics.isAnyActiveFlowFilePenalized());
3438
3439         return dto;
3440     }
3441
3442     private RemoteQueuePartitionDTO createRemoteQueuePartitionDto(final RemoteQueuePartitionDiagnostics queueDiagnostics) {
3443         final RemoteQueuePartitionDTO dto = new RemoteQueuePartitionDTO();
3444
3445         dto.setNodeIdentifier(queueDiagnostics.getNodeIdentifier());
3446
3447         final QueueSize activeSize = queueDiagnostics.getActiveQueueSize();
3448         dto.setActiveQueueByteCount(activeSize.getByteCount());
3449         dto.setActiveQueueFlowFileCount(activeSize.getObjectCount());
3450
3451         final QueueSize inFlightSize = queueDiagnostics.getUnacknowledgedQueueSize();
3452         dto.setInFlightByteCount(inFlightSize.getByteCount());
3453         dto.setInFlightFlowFileCount(inFlightSize.getObjectCount());
3454
3455         final QueueSize swapSize = queueDiagnostics.getSwapQueueSize();
3456         dto.setSwapByteCount(swapSize.getByteCount());
3457         dto.setSwapFlowFileCount(swapSize.getObjectCount());
3458         dto.setSwapFiles(queueDiagnostics.getSwapFileCount());
3459
3460         dto.setTotalByteCount(activeSize.getByteCount() + inFlightSize.getByteCount() + swapSize.getByteCount());
3461         dto.setTotalFlowFileCount(activeSize.getObjectCount() + inFlightSize.getObjectCount() + swapSize.getObjectCount());
3462
3463         return dto;
3464     }
3465
3466     private JVMDiagnosticsDTO createJvmDiagnosticsDto(final FlowController flowController) {
3467         final JVMDiagnosticsDTO dto = new JVMDiagnosticsDTO();
3468         dto.setAggregateSnapshot(createJvmDiagnosticsSnapshotDto(flowController));
3469         dto.setClustered(flowController.isClustered());
3470         dto.setConnected(flowController.isConnected());
3471         return dto;
3472     }
3473
3474     private JVMDiagnosticsSnapshotDTO createJvmDiagnosticsSnapshotDto(final FlowController flowController) {
3475         final JVMDiagnosticsSnapshotDTO dto = new JVMDiagnosticsSnapshotDTO();
3476
3477         final JVMControllerDiagnosticsSnapshotDTO controllerDiagnosticsDto = new JVMControllerDiagnosticsSnapshotDTO();
3478         final JVMFlowDiagnosticsSnapshotDTO flowDiagnosticsDto = new JVMFlowDiagnosticsSnapshotDTO();
3479         final JVMSystemDiagnosticsSnapshotDTO systemDiagnosticsDto = new JVMSystemDiagnosticsSnapshotDTO();
3480
3481         dto.setControllerDiagnostics(controllerDiagnosticsDto);
3482         dto.setFlowDiagnosticsDto(flowDiagnosticsDto);
3483         dto.setSystemDiagnosticsDto(systemDiagnosticsDto);
3484
3485         final SystemDiagnostics systemDiagnostics = flowController.getSystemDiagnostics();
3486
3487         // flow-related information
3488         final Set<BundleDTO> bundlesLoaded = extensionManager.getAllBundles().stream()
3489             .map(bundle -> bundle.getBundleDetails().getCoordinate())
3490             .sorted((a, b) -> a.getCoordinate().compareTo(b.getCoordinate()))
3491             .map(this::createBundleDto)
3492             .collect(Collectors.toCollection(LinkedHashSet::new));
3493
3494         flowDiagnosticsDto.setActiveEventDrivenThreads(flowController.getActiveEventDrivenThreadCount());
3495         flowDiagnosticsDto.setActiveTimerDrivenThreads(flowController.getActiveTimerDrivenThreadCount());
3496         flowDiagnosticsDto.setBundlesLoaded(bundlesLoaded);
3497         flowDiagnosticsDto.setTimeZone(System.getProperty("user.timezone"));
3498         flowDiagnosticsDto.setUptime(FormatUtils.formatHoursMinutesSeconds(systemDiagnostics.getUptime(), TimeUnit.MILLISECONDS));
3499
3500         // controller-related information
3501         controllerDiagnosticsDto.setClusterCoordinator(flowController.isClusterCoordinator());
3502         controllerDiagnosticsDto.setPrimaryNode(flowController.isPrimary());
3503         controllerDiagnosticsDto.setMaxEventDrivenThreads(flowController.getMaxEventDrivenThreadCount());
3504         controllerDiagnosticsDto.setMaxTimerDrivenThreads(flowController.getMaxTimerDrivenThreadCount());
3505
3506         // system-related information
3507         systemDiagnosticsDto.setMaxOpenFileDescriptors(systemDiagnostics.getMaxOpenFileHandles());
3508         systemDiagnosticsDto.setOpenFileDescriptors(systemDiagnostics.getOpenFileHandles());
3509         systemDiagnosticsDto.setPhysicalMemoryBytes(systemDiagnostics.getTotalPhysicalMemory());
3510         systemDiagnosticsDto.setPhysicalMemory(FormatUtils.formatDataSize(systemDiagnostics.getTotalPhysicalMemory()));
3511
3512         final NumberFormat percentageFormat = NumberFormat.getPercentInstance();
3513         percentageFormat.setMaximumFractionDigits(2);
3514
3515         final Set<RepositoryUsageDTO> contentRepoUsage = new HashSet<>();
3516         for (final Map.Entry<String, StorageUsage> entry : systemDiagnostics.getContentRepositoryStorageUsage().entrySet()) {
3517             final String repoName = entry.getKey();
3518             final StorageUsage usage = entry.getValue();
3519
3520             final RepositoryUsageDTO usageDto = new RepositoryUsageDTO();
3521             usageDto.setName(repoName);
3522
3523             usageDto.setFileStoreHash(DigestUtils.sha256Hex(flowController.getContentRepoFileStoreName(repoName)));
3524             usageDto.setFreeSpace(FormatUtils.formatDataSize(usage.getFreeSpace()));
3525             usageDto.setFreeSpaceBytes(usage.getFreeSpace());
3526             usageDto.setTotalSpace(FormatUtils.formatDataSize(usage.getTotalSpace()));
3527             usageDto.setTotalSpaceBytes(usage.getTotalSpace());
3528
3529             final double usedPercentage = (usage.getTotalSpace() - usage.getFreeSpace()) / (double) usage.getTotalSpace();
3530             final String utilization = percentageFormat.format(usedPercentage);
3531             usageDto.setUtilization(utilization);
3532             contentRepoUsage.add(usageDto);
3533         }
3534
3535         final Set<RepositoryUsageDTO> provRepoUsage = new HashSet<>();
3536         for (final Map.Entry<String, StorageUsage> entry : systemDiagnostics.getProvenanceRepositoryStorageUsage().entrySet()) {
3537             final String repoName = entry.getKey();
3538             final StorageUsage usage = entry.getValue();
3539
3540             final RepositoryUsageDTO usageDto = new RepositoryUsageDTO();
3541             usageDto.setName(repoName);
3542
3543             usageDto.setFileStoreHash(DigestUtils.sha256Hex(flowController.getProvenanceRepoFileStoreName(repoName)));
3544             usageDto.setFreeSpace(FormatUtils.formatDataSize(usage.getFreeSpace()));
3545             usageDto.setFreeSpaceBytes(usage.getFreeSpace());
3546             usageDto.setTotalSpace(FormatUtils.formatDataSize(usage.getTotalSpace()));
3547             usageDto.setTotalSpaceBytes(usage.getTotalSpace());
3548
3549             final double usedPercentage = (usage.getTotalSpace() - usage.getFreeSpace()) / (double) usage.getTotalSpace();
3550             final String utilization = percentageFormat.format(usedPercentage);
3551             usageDto.setUtilization(utilization);
3552             provRepoUsage.add(usageDto);
3553         }
3554
3555         final RepositoryUsageDTO flowFileRepoUsage = new RepositoryUsageDTO();
3556         for (final Map.Entry<String, StorageUsage> entry : systemDiagnostics.getProvenanceRepositoryStorageUsage().entrySet()) {
3557             final String repoName = entry.getKey();
3558             final StorageUsage usage = entry.getValue();
3559
3560             flowFileRepoUsage.setName(repoName);
3561
3562             flowFileRepoUsage.setFileStoreHash(DigestUtils.sha256Hex(flowController.getFlowRepoFileStoreName()));
3563             flowFileRepoUsage.setFreeSpace(FormatUtils.formatDataSize(usage.getFreeSpace()));
3564             flowFileRepoUsage.setFreeSpaceBytes(usage.getFreeSpace());
3565             flowFileRepoUsage.setTotalSpace(FormatUtils.formatDataSize(usage.getTotalSpace()));
3566             flowFileRepoUsage.setTotalSpaceBytes(usage.getTotalSpace());
3567
3568             final double usedPercentage = (usage.getTotalSpace() - usage.getFreeSpace()) / (double) usage.getTotalSpace();
3569             final String utilization = percentageFormat.format(usedPercentage);
3570             flowFileRepoUsage.setUtilization(utilization);
3571         }
3572
3573         systemDiagnosticsDto.setContentRepositoryStorageUsage(contentRepoUsage);
3574         systemDiagnosticsDto.setCpuCores(systemDiagnostics.getAvailableProcessors());
3575         systemDiagnosticsDto.setCpuLoadAverage(systemDiagnostics.getProcessorLoadAverage());
3576         systemDiagnosticsDto.setFlowFileRepositoryStorageUsage(flowFileRepoUsage);
3577         systemDiagnosticsDto.setMaxHeapBytes(systemDiagnostics.getMaxHeap());
3578         systemDiagnosticsDto.setMaxHeap(FormatUtils.formatDataSize(systemDiagnostics.getMaxHeap()));
3579         systemDiagnosticsDto.setProvenanceRepositoryStorageUsage(provRepoUsage);
3580
3581         // Create the Garbage Collection History info
3582         final GarbageCollectionHistory gcHistory = flowController.getGarbageCollectionHistory();
3583         final List<GarbageCollectionDiagnosticsDTO> gcDiagnostics = new ArrayList<>();
3584         for (final String memoryManager : gcHistory.getMemoryManagerNames()) {
3585             final List<GarbageCollectionStatus> statuses = gcHistory.getGarbageCollectionStatuses(memoryManager);
3586
3587             final List<GCDiagnosticsSnapshotDTO> gcSnapshots = new ArrayList<>();
3588             for (final GarbageCollectionStatus status : statuses) {
3589                 final GCDiagnosticsSnapshotDTO snapshotDto = new GCDiagnosticsSnapshotDTO();
3590                 snapshotDto.setTimestamp(status.getTimestamp());
3591                 snapshotDto.setCollectionCount(status.getCollectionCount());
3592                 snapshotDto.setCollectionMillis(status.getCollectionMillis());
3593                 gcSnapshots.add(snapshotDto);
3594             }
3595
3596             gcSnapshots.sort(Comparator.comparing(GCDiagnosticsSnapshotDTO::getTimestamp).reversed());
3597
3598             final GarbageCollectionDiagnosticsDTO gcDto = new GarbageCollectionDiagnosticsDTO();
3599             gcDto.setMemoryManagerName(memoryManager);
3600             gcDto.setSnapshots(gcSnapshots);
3601             gcDiagnostics.add(gcDto);
3602         }
3603
3604         systemDiagnosticsDto.setGarbageCollectionDiagnostics(gcDiagnostics);
3605
3606         return dto;
3607     }
3608
3609     private List<ThreadDumpDTO> createThreadDumpDtos(final ProcessorNode procNode) {
3610         final List<ThreadDumpDTO> threadDumps = new ArrayList<>();
3611
3612         final List<ActiveThreadInfo> activeThreads = procNode.getActiveThreads();
3613         for (final ActiveThreadInfo threadInfo : activeThreads) {
3614             final ThreadDumpDTO dto = new ThreadDumpDTO();
3615             dto.setStackTrace(threadInfo.getStackTrace());
3616             dto.setThreadActiveMillis(threadInfo.getActiveMillis());
3617             dto.setThreadName(threadInfo.getThreadName());
3618             dto.setTaskTerminated(threadInfo.isTerminated());
3619             threadDumps.add(dto);
3620         }
3621
3622         return threadDumps;
3623     }
3624
3625     /**
3626      * Creates a ProcessorConfigDTO from the specified ProcessorNode.
3627      *
3628      * @param procNode node
3629      * @return dto
3630      */
3631     public ProcessorConfigDTO createProcessorConfigDto(final ProcessorNode procNode) {
3632         if (procNode == null) {
3633             return null;
3634         }
3635
3636         final ProcessorConfigDTO dto = new ProcessorConfigDTO();
3637
3638         // sort a copy of the properties
3639         final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() {
3640             @Override
3641             public int compare(final PropertyDescriptor o1, final PropertyDescriptor o2) {
3642                 return Collator.getInstance(Locale.US).compare(o1.getName(), o2.getName());
3643             }
3644         });
3645         sortedProperties.putAll(procNode.getProperties());
3646
3647         // get the property order from the processor
3648         final Processor processor = procNode.getProcessor();
3649         final Map<PropertyDescriptor, String> orderedProperties = new LinkedHashMap<>();
3650         final List<PropertyDescriptor> descriptors = processor.getPropertyDescriptors();
3651         if (descriptors != null && !descriptors.isEmpty()) {
3652             for (final PropertyDescriptor descriptor : descriptors) {
3653                 orderedProperties.put(descriptor, null);
3654             }
3655         }
3656         orderedProperties.putAll(sortedProperties);
3657
3658         // build the descriptor and property dtos
3659         dto.setDescriptors(new LinkedHashMap<String, PropertyDescriptorDTO>());
3660         dto.setProperties(new LinkedHashMap<String, String>());
3661         for (final Map.Entry<PropertyDescriptor, String> entry : orderedProperties.entrySet()) {
3662             final PropertyDescriptor descriptor = entry.getKey();
3663
3664             // store the property descriptor
3665             dto.getDescriptors().put(descriptor.getName(), createPropertyDescriptorDto(descriptor, procNode.getProcessGroup().getIdentifier()));
3666
3667             // determine the property value - don't include sensitive properties
3668             String propertyValue = entry.getValue();
3669             if (propertyValue != null && descriptor.isSensitive()) {
3670                 propertyValue = SENSITIVE_VALUE_MASK;
3671             } else if (propertyValue == null && descriptor.getDefaultValue() != null) {
3672                 propertyValue = descriptor.getDefaultValue();
3673             }
3674
3675             // set the property value
3676             dto.getProperties().put(descriptor.getName(), propertyValue);
3677         }
3678
3679         dto.setSchedulingPeriod(procNode.getSchedulingPeriod());
3680         dto.setPenaltyDuration(procNode.getPenalizationPeriod());
3681         dto.setYieldDuration(procNode.getYieldPeriod());
3682         dto.setRunDurationMillis(procNode.getRunDuration(TimeUnit.MILLISECONDS));
3683         dto.setConcurrentlySchedulableTaskCount(procNode.getMaxConcurrentTasks());
3684         dto.setLossTolerant(procNode.isLossTolerant());
3685         dto.setComments(procNode.getComments());
3686         dto.setBulletinLevel(procNode.getBulletinLevel().name());
3687         dto.setSchedulingStrategy(procNode.getSchedulingStrategy().name());
3688         dto.setExecutionNode(procNode.getExecutionNode().name());
3689         dto.setAnnotationData(procNode.getAnnotationData());
3690
3691         // set up the default values for concurrent tasks and scheduling period
3692         final Map<String, String> defaultConcurrentTasks = new HashMap<>();
3693         defaultConcurrentTasks.put(SchedulingStrategy.TIMER_DRIVEN.name(), String.valueOf(SchedulingStrategy.TIMER_DRIVEN.getDefaultConcurrentTasks()));
3694         defaultConcurrentTasks.put(SchedulingStrategy.EVENT_DRIVEN.name(), String.valueOf(SchedulingStrategy.EVENT_DRIVEN.getDefaultConcurrentTasks()));
3695         defaultConcurrentTasks.put(SchedulingStrategy.CRON_DRIVEN.name(), String.valueOf(SchedulingStrategy.CRON_DRIVEN.getDefaultConcurrentTasks()));
3696         dto.setDefaultConcurrentTasks(defaultConcurrentTasks);
3697
3698         final Map<String, String> defaultSchedulingPeriod = new HashMap<>();
3699         defaultSchedulingPeriod.put(SchedulingStrategy.TIMER_DRIVEN.name(), SchedulingStrategy.TIMER_DRIVEN.getDefaultSchedulingPeriod());
3700         defaultSchedulingPeriod.put(SchedulingStrategy.CRON_DRIVEN.name(), SchedulingStrategy.CRON_DRIVEN.getDefaultSchedulingPeriod());
3701         dto.setDefaultSchedulingPeriod(defaultSchedulingPeriod);
3702
3703         return dto;
3704     }
3705
3706     /**
3707      * Creates a PropertyDesriptorDTO from the specified PropertyDesriptor.
3708      *
3709      * @param propertyDescriptor descriptor
3710      * @param groupId the Identifier of the Process Group that the component belongs to
3711      * @return dto
3712      */
3713     public PropertyDescriptorDTO createPropertyDescriptorDto(final PropertyDescriptor propertyDescriptor, final String groupId) {
3714         if (propertyDescriptor == null) {
3715             return null;
3716         }
3717
3718         final PropertyDescriptorDTO dto = new PropertyDescriptorDTO();
3719
3720         dto.setName(propertyDescriptor.getName());
3721         dto.setDisplayName(propertyDescriptor.getDisplayName());
3722         dto.setRequired(propertyDescriptor.isRequired());
3723         dto.setSensitive(propertyDescriptor.isSensitive());
3724         dto.setDynamic(propertyDescriptor.isDynamic());
3725         dto.setDescription(propertyDescriptor.getDescription());
3726         dto.setDefaultValue(propertyDescriptor.getDefaultValue());
3727         dto.setSupportsEl(propertyDescriptor.isExpressionLanguageSupported());
3728
3729         // to support legacy/deprecated method .expressionLanguageSupported(true)
3730         String description = propertyDescriptor.isExpressionLanguageSupported()
3731                 && propertyDescriptor.getExpressionLanguageScope().equals(ExpressionLanguageScope.NONE)
3732                 ? "true (undefined scope)" : propertyDescriptor.getExpressionLanguageScope().getDescription();
3733         dto.setExpressionLanguageScope(description);
3734
3735         // set the identifies controller service is applicable
3736         if (propertyDescriptor.getControllerServiceDefinition() != null) {
3737             final Class serviceClass = propertyDescriptor.getControllerServiceDefinition();
3738             final Bundle serviceBundle = extensionManager.getBundle(serviceClass.getClassLoader());
3739
3740             dto.setIdentifiesControllerService(serviceClass.getName());
3741             dto.setIdentifiesControllerServiceBundle(createBundleDto(serviceBundle.getBundleDetails().getCoordinate()));
3742         }
3743
3744         final Class<? extends ControllerService> serviceDefinition = propertyDescriptor.getControllerServiceDefinition();
3745         if (propertyDescriptor.getAllowableValues() == null) {
3746             if (serviceDefinition == null) {
3747                 dto.setAllowableValues(null);
3748             } else {
3749                 final List<AllowableValueEntity> allowableValues = new ArrayList<>();
3750                 final List<String> controllerServiceIdentifiers = new ArrayList<>(controllerServiceProvider.getControllerServiceIdentifiers(serviceDefinition, groupId));
3751                 Collections.sort(controllerServiceIdentifiers, Collator.getInstance(Locale.US));
3752                 for (final String serviceIdentifier : controllerServiceIdentifiers) {
3753                     final ControllerServiceNode service = controllerServiceProvider.getControllerServiceNode(serviceIdentifier);
3754                     final boolean isServiceAuthorized = service.isAuthorized(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
3755                     final String displayName = isServiceAuthorized ? service.getName() : serviceIdentifier;
3756
3757                     final AllowableValueDTO allowableValue = new AllowableValueDTO();
3758                     allowableValue.setDisplayName(displayName);
3759                     allowableValue.setValue(serviceIdentifier);
3760                     allowableValues.add(entityFactory.createAllowableValueEntity(allowableValue, isServiceAuthorized));
3761                 }
3762                 dto.setAllowableValues(allowableValues);
3763             }
3764         } else {
3765             final List<AllowableValueEntity> allowableValues = new ArrayList<>();
3766             for (final AllowableValue allowableValue : propertyDescriptor.getAllowableValues()) {
3767                 final AllowableValueDTO allowableValueDto = new AllowableValueDTO();
3768                 allowableValueDto.setDisplayName(allowableValue.getDisplayName());
3769                 allowableValueDto.setValue(allowableValue.getValue());
3770                 allowableValueDto.setDescription(allowableValue.getDescription());
3771                 allowableValues.add(entityFactory.createAllowableValueEntity(allowableValueDto, true));
3772             }
3773
3774             dto.setAllowableValues(allowableValues);
3775         }
3776
3777         return dto;
3778     }
3779
3780     // Copy methods
3781     public LabelDTO copy(final LabelDTO original) {
3782         final LabelDTO copy = new LabelDTO();
3783         copy.setId(original.getId());
3784         copy.setParentGroupId(original.getParentGroupId());
3785         copy.setLabel(original.getLabel());
3786         copy.setStyle(copy(original.getStyle()));
3787         copy.setPosition(original.getPosition());
3788         copy.setWidth(original.getWidth());
3789         copy.setHeight(original.getHeight());
3790         copy.setVersionedComponentId(original.getVersionedComponentId());
3791
3792         return copy;
3793     }
3794
3795     public ControllerServiceDTO copy(final ControllerServiceDTO original) {
3796         final ControllerServiceDTO copy = new ControllerServiceDTO();
3797         copy.setAnnotationData(original.getAnnotationData());
3798         copy.setControllerServiceApis(original.getControllerServiceApis());
3799         copy.setComments(original.getComments());
3800         copy.setCustomUiUrl(original.getCustomUiUrl());
3801         copy.setDescriptors(copy(original.getDescriptors()));
3802         copy.setId(original.getId());
3803         copy.setParentGroupId(original.getParentGroupId());
3804         copy.setName(original.getName());
3805         copy.setProperties(copy(original.getProperties()));
3806         copy.setReferencingComponents(copy(original.getReferencingComponents()));
3807         copy.setState(original.getState());
3808         copy.setType(original.getType());
3809         copy.setBundle(copy(original.getBundle()));
3810         copy.setExtensionMissing(original.getExtensionMissing());
3811         copy.setMultipleVersionsAvailable(original.getMultipleVersionsAvailable());
3812         copy.setPersistsState(original.getPersistsState());
3813         copy.setValidationErrors(copy(original.getValidationErrors()));
3814         copy.setValidationStatus(original.getValidationStatus());
3815         copy.setVersionedComponentId(original.getVersionedComponentId());
3816         return copy;
3817     }
3818
3819     public FunnelDTO copy(final FunnelDTO original) {
3820         final FunnelDTO copy = new FunnelDTO();
3821         copy.setId(original.getId());
3822         copy.setParentGroupId(original.getParentGroupId());
3823         copy.setPosition(original.getPosition());
3824         copy.setVersionedComponentId(original.getVersionedComponentId());
3825
3826         return copy;
3827     }
3828
3829     private <T> List<T> copy(final List<T> original) {
3830         if (original == null) {
3831             return null;
3832         } else {
3833             return new ArrayList<>(original);
3834         }
3835     }
3836
3837     private <T> List<T> copy(final Collection<T> original) {
3838         if (original == null) {
3839             return null;
3840         } else {
3841             return new ArrayList<>(original);
3842         }
3843     }
3844
3845     private <T> Set<T> copy(final Set<T> original) {
3846         if (original == null) {
3847             return null;
3848         } else {
3849             return new LinkedHashSet<>(original);
3850         }
3851     }
3852
3853     private <S, T> Map<S, T> copy(final Map<S, T> original) {
3854         if (original == null) {
3855             return null;
3856         } else {
3857             return new LinkedHashMap<>(original);
3858         }
3859     }
3860
3861     public BundleDTO copy(final BundleDTO original) {
3862         if (original == null) {
3863             return null;
3864         }
3865
3866         final BundleDTO copy = new BundleDTO();
3867         copy.setGroup(original.getGroup());
3868         copy.setArtifact(original.getArtifact());
3869         copy.setVersion(original.getVersion());
3870         return copy;
3871     }
3872
3873     public ProcessorDTO copy(final ProcessorDTO original) {
3874         final ProcessorDTO copy = new ProcessorDTO();
3875         copy.setConfig(copy(original.getConfig()));
3876         copy.setPosition(original.getPosition());
3877         copy.setId(original.getId());
3878         copy.setName(original.getName());
3879         copy.setDescription(original.getDescription());
3880         copy.setParentGroupId(original.getParentGroupId());
3881         copy.setRelationships(copy(original.getRelationships()));
3882         copy.setState(original.getState());
3883         copy.setStyle(copy(original.getStyle()));
3884         copy.setType(original.getType());
3885         copy.setBundle(copy(original.getBundle()));
3886         copy.setSupportsParallelProcessing(original.getSupportsParallelProcessing());
3887         copy.setSupportsEventDriven(original.getSupportsEventDriven());
3888         copy.setSupportsBatching(original.getSupportsBatching());
3889         copy.setPersistsState(original.getPersistsState());
3890         copy.setExecutionNodeRestricted(original.isExecutionNodeRestricted());
3891         copy.setExtensionMissing(original.getExtensionMissing());
3892         copy.setMultipleVersionsAvailable(original.getMultipleVersionsAvailable());
3893         copy.setValidationErrors(copy(original.getValidationErrors()));
3894         copy.setValidationStatus(original.getValidationStatus());
3895         copy.setVersionedComponentId(original.getVersionedComponentId());
3896
3897         return copy;
3898     }
3899
3900     private ProcessorConfigDTO copy(final ProcessorConfigDTO original) {
3901         final ProcessorConfigDTO copy = new ProcessorConfigDTO();
3902         copy.setAnnotationData(original.getAnnotationData());
3903         copy.setAutoTerminatedRelationships(copy(original.getAutoTerminatedRelationships()));
3904         copy.setComments(original.getComments());
3905         copy.setSchedulingStrategy(original.getSchedulingStrategy());
3906         copy.setExecutionNode(original.getExecutionNode());
3907         copy.setConcurrentlySchedulableTaskCount(original.getConcurrentlySchedulableTaskCount());
3908         copy.setCustomUiUrl(original.getCustomUiUrl());
3909         copy.setDescriptors(copy(original.getDescriptors()));
3910         copy.setProperties(copy(original.getProperties()));
3911         copy.setSchedulingPeriod(original.getSchedulingPeriod());
3912         copy.setPenaltyDuration(original.getPenaltyDuration());
3913         copy.setYieldDuration(original.getYieldDuration());
3914         copy.setRunDurationMillis(original.getRunDurationMillis());
3915         copy.setBulletinLevel(original.getBulletinLevel());
3916         copy.setDefaultConcurrentTasks(original.getDefaultConcurrentTasks());
3917         copy.setDefaultSchedulingPeriod(original.getDefaultSchedulingPeriod());
3918         copy.setLossTolerant(original.isLossTolerant());
3919
3920         return copy;
3921     }
3922
3923     public ConnectionDTO copy(final ConnectionDTO original) {
3924         final ConnectionDTO copy = new ConnectionDTO();
3925         copy.setAvailableRelationships(copy(original.getAvailableRelationships()));
3926         copy.setDestination(original.getDestination());
3927         copy.setPosition(original.getPosition());
3928         copy.setId(original.getId());
3929         copy.setName(original.getName());
3930         copy.setParentGroupId(original.getParentGroupId());
3931         copy.setSelectedRelationships(copy(original.getSelectedRelationships()));
3932         copy.setFlowFileExpiration(original.getFlowFileExpiration());
3933         copy.setBackPressureObjectThreshold(original.getBackPressureObjectThreshold());
3934         copy.setBackPressureDataSizeThreshold(original.getBackPressureDataSizeThreshold());
3935         copy.setPrioritizers(copy(original.getPrioritizers()));
3936         copy.setSource(original.getSource());
3937         copy.setzIndex(original.getzIndex());
3938         copy.setLabelIndex(original.getLabelIndex());
3939         copy.setBends(copy(original.getBends()));
3940         copy.setLoadBalancePartitionAttribute(original.getLoadBalancePartitionAttribute());
3941         copy.setLoadBalanceStrategy(original.getLoadBalanceStrategy());
3942         copy.setLoadBalanceCompression(original.getLoadBalanceCompression());
3943         copy.setLoadBalanceStatus(original.getLoadBalanceStatus());
3944         copy.setVersionedComponentId(original.getVersionedComponentId());
3945
3946         return copy;
3947     }
3948
3949     public BulletinDTO copy(final BulletinDTO original) {
3950         final BulletinDTO copy = new BulletinDTO();
3951         copy.setId(original.getId());
3952         copy.setTimestamp(original.getTimestamp());
3953         copy.setGroupId(original.getGroupId());
3954         copy.setSourceId(original.getSourceId());
3955         copy.setSourceName(original.getSourceName());
3956         copy.setCategory(original.getCategory());
3957         copy.setLevel(original.getLevel());
3958         copy.setMessage(original.getMessage());
3959         copy.setNodeAddress(original.getNodeAddress());
3960         return copy;
3961     }
3962
3963     public PortDTO copy(final PortDTO original) {
3964         final PortDTO copy = new PortDTO();
3965         copy.setPosition(original.getPosition());
3966         copy.setId(original.getId());
3967         copy.setName(original.getName());
3968         copy.setComments(original.getComments());
3969         copy.setParentGroupId(original.getParentGroupId());
3970         copy.setState(original.getState());
3971         copy.setType(original.getType());
3972         copy.setTransmitting(original.isTransmitting());
3973         copy.setConcurrentlySchedulableTaskCount(original.getConcurrentlySchedulableTaskCount());
3974         copy.setUserAccessControl(copy(original.getUserAccessControl()));
3975         copy.setGroupAccessControl(copy(original.getGroupAccessControl()));
3976         copy.setValidationErrors(copy(original.getValidationErrors()));
3977         copy.setVersionedComponentId(original.getVersionedComponentId());
3978         return copy;
3979     }
3980
3981     public RemoteProcessGroupPortDTO copy(final RemoteProcessGroupPortDTO original) {
3982         final RemoteProcessGroupPortDTO copy = new RemoteProcessGroupPortDTO();
3983         copy.setId(original.getId());
3984         copy.setTargetId(original.getTargetId());
3985         copy.setGroupId(original.getGroupId());
3986         copy.setName(original.getName());
3987         copy.setComments(original.getComments());
3988         copy.setConnected(original.isConnected());
3989         copy.setTargetRunning(original.isTargetRunning());
3990         copy.setTransmitting(original.isTransmitting());
3991         copy.setConcurrentlySchedulableTaskCount(original.getConcurrentlySchedulableTaskCount());
3992         copy.setUseCompression(original.getUseCompression());
3993         copy.setExists(original.getExists());
3994         copy.setVersionedComponentId(original.getVersionedComponentId());
3995
3996         final BatchSettingsDTO batchOrg = original.getBatchSettings();
3997         if (batchOrg != null) {
3998             final BatchSettingsDTO batchCopy = new BatchSettingsDTO();
3999             batchCopy.setCount(batchOrg.getCount());
4000             batchCopy.setSize(batchOrg.getSize());
4001             batchCopy.setDuration(batchOrg.getDuration());
4002             copy.setBatchSettings(batchCopy);
4003         }
4004         return copy;
4005     }
4006
4007     public ProcessGroupDTO copy(final ProcessGroupDTO original, final boolean deep) {
4008         final ProcessGroupDTO copy = new ProcessGroupDTO();
4009         copy.setComments(original.getComments());
4010         copy.setContents(copy(original.getContents(), deep));
4011         copy.setPosition(original.getPosition());
4012         copy.setId(original.getId());
4013         copy.setInputPortCount(original.getInputPortCount());
4014         copy.setInvalidCount(original.getInvalidCount());
4015         copy.setName(original.getName());
4016         copy.setVersionControlInformation(copy(original.getVersionControlInformation()));
4017         copy.setOutputPortCount(original.getOutputPortCount());
4018         copy.setParentGroupId(original.getParentGroupId());
4019         copy.setVersionedComponentId(original.getVersionedComponentId());
4020
4021         copy.setRunningCount(original.getRunningCount());
4022         copy.setStoppedCount(original.getStoppedCount());
4023         copy.setDisabledCount(original.getDisabledCount());
4024         copy.setActiveRemotePortCount(original.getActiveRemotePortCount());
4025         copy.setInactiveRemotePortCount(original.getInactiveRemotePortCount());
4026
4027         copy.setUpToDateCount(original.getUpToDateCount());
4028         copy.setLocallyModifiedCount(original.getLocallyModifiedCount());
4029         copy.setStaleCount(original.getStaleCount());
4030         copy.setLocallyModifiedAndStaleCount(original.getLocallyModifiedAndStaleCount());
4031         copy.setSyncFailureCount(original.getSyncFailureCount());
4032
4033         if (original.getVariables() != null) {
4034             copy.setVariables(new HashMap<>(original.getVariables()));
4035         }
4036
4037         return copy;
4038     }
4039
4040     public VersionControlInformationDTO copy(final VersionControlInformationDTO original) {
4041         if (original == null) {
4042             return null;
4043         }
4044
4045         final VersionControlInformationDTO copy = new VersionControlInformationDTO();
4046         copy.setRegistryId(original.getRegistryId());
4047         copy.setRegistryName(original.getRegistryName());
4048         copy.setBucketId(original.getBucketId());
4049         copy.setBucketName(original.getBucketName());
4050         copy.setFlowId(original.getFlowId());
4051         copy.setFlowName(original.getFlowName());
4052         copy.setFlowDescription(original.getFlowDescription());
4053         copy.setVersion(original.getVersion());
4054         copy.setState(original.getState());
4055         copy.setStateExplanation(original.getStateExplanation());
4056         return copy;
4057     }
4058
4059     public RemoteProcessGroupDTO copy(final RemoteProcessGroupDTO original) {
4060         final RemoteProcessGroupContentsDTO originalContents = original.getContents();
4061         final RemoteProcessGroupContentsDTO copyContents = new RemoteProcessGroupContentsDTO();
4062
4063         if (originalContents.getInputPorts() != null) {
4064             final Set<RemoteProcessGroupPortDTO> inputPorts = new HashSet<>();
4065             for (final RemoteProcessGroupPortDTO port : originalContents.getInputPorts()) {
4066                 inputPorts.add(copy(port));
4067             }
4068             copyContents.setInputPorts(inputPorts);
4069         }
4070
4071         if (originalContents.getOutputPorts() != null) {
4072             final Set<RemoteProcessGroupPortDTO> outputPorts = new HashSet<>();
4073             for (final RemoteProcessGroupPortDTO port : originalContents.getOutputPorts()) {
4074                 outputPorts.add(copy(port));
4075             }
4076             copyContents.setOutputPorts(outputPorts);
4077         }
4078
4079         final RemoteProcessGroupDTO copy = new RemoteProcessGroupDTO();
4080         copy.setComments(original.getComments());
4081         copy.setPosition(original.getPosition());
4082         copy.setId(original.getId());
4083         copy.setCommunicationsTimeout(original.getCommunicationsTimeout());
4084         copy.setYieldDuration(original.getYieldDuration());
4085         copy.setName(original.getName());
4086         copy.setInputPortCount(original.getInputPortCount());
4087         copy.setOutputPortCount(original.getOutputPortCount());
4088         copy.setActiveRemoteInputPortCount(original.getActiveRemoteInputPortCount());
4089         copy.setInactiveRemoteInputPortCount(original.getInactiveRemoteInputPortCount());
4090         copy.setActiveRemoteOutputPortCount(original.getActiveRemoteOutputPortCount());
4091         copy.setInactiveRemoteOutputPortCount(original.getInactiveRemoteOutputPortCount());
4092         copy.setParentGroupId(original.getParentGroupId());
4093         copy.setTargetUris(original.getTargetUris());
4094         copy.setTransportProtocol(original.getTransportProtocol());
4095         copy.setProxyHost(original.getProxyHost());
4096         copy.setProxyPort(original.getProxyPort());
4097         copy.setProxyUser(original.getProxyUser());
4098         copy.setProxyPassword(original.getProxyPassword());
4099         copy.setLocalNetworkInterface(original.getLocalNetworkInterface());
4100         copy.setVersionedComponentId(original.getVersionedComponentId());
4101
4102         copy.setContents(copyContents);
4103
4104         return copy;
4105     }
4106
4107     public ConnectableDTO createConnectableDto(final PortDTO port, final ConnectableType type) {
4108         final ConnectableDTO connectable = new ConnectableDTO();
4109         connectable.setGroupId(port.getParentGroupId());
4110         connectable.setId(port.getId());
4111         connectable.setName(port.getName());
4112         connectable.setType(type.name());
4113         connectable.setVersionedComponentId(port.getVersionedComponentId());
4114         return connectable;
4115     }
4116
4117     public ConnectableDTO createConnectableDto(final ProcessorDTO processor) {
4118         final ConnectableDTO connectable = new ConnectableDTO();
4119         connectable.setGroupId(processor.getParentGroupId());
4120         connectable.setId(processor.getId());
4121         connectable.setName(processor.getName());
4122         connectable.setType(ConnectableType.PROCESSOR.name());
4123         connectable.setVersionedComponentId(processor.getVersionedComponentId());
4124         return connectable;
4125     }
4126
4127     public ConnectableDTO createConnectableDto(final FunnelDTO funnel) {
4128         final ConnectableDTO connectable = new ConnectableDTO();
4129         connectable.setGroupId(funnel.getParentGroupId());
4130         connectable.setId(funnel.getId());
4131         connectable.setType(ConnectableType.FUNNEL.name());
4132         connectable.setVersionedComponentId(funnel.getVersionedComponentId());
4133         return connectable;
4134     }
4135
4136     public ConnectableDTO createConnectableDto(final RemoteProcessGroupPortDTO remoteGroupPort, final ConnectableType type) {
4137         final ConnectableDTO connectable = new ConnectableDTO();
4138         connectable.setGroupId(remoteGroupPort.getGroupId());
4139         connectable.setId(remoteGroupPort.getId());
4140         connectable.setName(remoteGroupPort.getName());
4141         connectable.setType(type.name());
4142         connectable.setVersionedComponentId(connectable.getVersionedComponentId());
4143         return connectable;
4144     }
4145
4146     /**
4147      *
4148      * @param original orig
4149      * @param deep if <code>true</code>, all Connections, ProcessGroups, Ports, Processors, etc. will be copied. If <code>false</code>, the copy will have links to the same objects referenced by
4150      * <code>original</code>.
4151      *
4152      * @return dto
4153      */
4154     private FlowSnippetDTO copy(final FlowSnippetDTO original, final boolean deep) {
4155         final FlowSnippetDTO copy = new FlowSnippetDTO();
4156
4157         final Set<ConnectionDTO> connections = new LinkedHashSet<>();
4158         final Set<ProcessGroupDTO> groups = new LinkedHashSet<>();
4159         final Set<PortDTO> inputPorts = new LinkedHashSet<>();
4160         final Set<PortDTO> outputPorts = new LinkedHashSet<>();
4161         final Set<LabelDTO> labels = new LinkedHashSet<>();
4162         final Set<ProcessorDTO> processors = new LinkedHashSet<>();
4163         final Set<RemoteProcessGroupDTO> remoteProcessGroups = new LinkedHashSet<>();
4164         final Set<FunnelDTO> funnels = new LinkedHashSet<>();
4165         final Set<ControllerServiceDTO> controllerServices = new LinkedHashSet<>();
4166
4167         if (deep) {
4168             for (final ProcessGroupDTO group : original.getProcessGroups()) {
4169                 groups.add(copy(group, deep));
4170             }
4171
4172             for (final PortDTO port : original.getInputPorts()) {
4173                 inputPorts.add(copy(port));
4174             }
4175
4176             for (final PortDTO port : original.getOutputPorts()) {
4177                 outputPorts.add(copy(port));
4178             }
4179
4180             for (final LabelDTO label : original.getLabels()) {
4181                 labels.add(copy(label));
4182             }
4183
4184             for (final ProcessorDTO processor : original.getProcessors()) {
4185                 processors.add(copy(processor));
4186             }
4187
4188             for (final RemoteProcessGroupDTO remoteGroup : original.getRemoteProcessGroups()) {
4189                 remoteProcessGroups.add(copy(remoteGroup));
4190             }
4191
4192             for (final FunnelDTO funnel : original.getFunnels()) {
4193                 funnels.add(copy(funnel));
4194             }
4195
4196             for (final ConnectionDTO connection : original.getConnections()) {
4197                 connections.add(copy(connection));
4198             }
4199
4200             for (final ControllerServiceDTO controllerService : original.getControllerServices()) {
4201                 controllerServices.add(copy(controllerService));
4202             }
4203         } else {
4204             if (original.getConnections() != null) {
4205                 connections.addAll(copy(original.getConnections()));
4206             }
4207             if (original.getProcessGroups() != null) {
4208                 groups.addAll(copy(original.getProcessGroups()));
4209             }
4210             if (original.getInputPorts() != null) {
4211                 inputPorts.addAll(copy(original.getInputPorts()));
4212             }
4213             if (original.getOutputPorts() != null) {
4214                 outputPorts.addAll(copy(original.getOutputPorts()));
4215             }
4216             if (original.getLabels() != null) {
4217                 labels.addAll(copy(original.getLabels()));
4218             }
4219             if (original.getProcessors() != null) {
4220                 processors.addAll(copy(original.getProcessors()));
4221             }
4222             if (original.getRemoteProcessGroups() != null) {
4223                 remoteProcessGroups.addAll(copy(original.getRemoteProcessGroups()));
4224             }
4225             if (original.getFunnels() != null) {
4226                 funnels.addAll(copy(original.getFunnels()));
4227             }
4228             if (original.getControllerServices() != null) {
4229                 controllerServices.addAll(copy(original.getControllerServices()));
4230             }
4231         }
4232
4233         copy.setConnections(connections);
4234         copy.setProcessGroups(groups);
4235         copy.setInputPorts(inputPorts);
4236         copy.setLabels(labels);
4237         copy.setOutputPorts(outputPorts);
4238         copy.setProcessors(processors);
4239         copy.setRemoteProcessGroups(remoteProcessGroups);
4240         copy.setFunnels(funnels);
4241         copy.setControllerServices(controllerServices);
4242
4243         return copy;
4244     }
4245
4246     /**
4247      * Factory method for creating a new RevisionDTO based on this controller.
4248      *
4249      * @param lastMod mod
4250      * @return dto
4251      */
4252     public RevisionDTO createRevisionDTO(final FlowModification lastMod) {
4253         final Revision revision = lastMod.getRevision();
4254
4255         // create the dto
4256         final RevisionDTO revisionDTO = new RevisionDTO();
4257         revisionDTO.setVersion(revision.getVersion());
4258         revisionDTO.setClientId(revision.getClientId());
4259         revisionDTO.setLastModifier(lastMod.getLastModifier());
4260
4261         return revisionDTO;
4262     }
4263
4264     public RevisionDTO createRevisionDTO(final Revision revision) {
4265         final RevisionDTO dto = new RevisionDTO();
4266         dto.setVersion(revision.getVersion());
4267         dto.setClientId(revision.getClientId());
4268         return dto;
4269     }
4270
4271     public NodeDTO createNodeDTO(final NodeIdentifier nodeId, final NodeConnectionStatus status, final NodeHeartbeat nodeHeartbeat, final List<NodeEvent> events, final Set<String> roles) {
4272         final NodeDTO nodeDto = new NodeDTO();
4273
4274         // populate node dto
4275         nodeDto.setNodeId(nodeId.getId());
4276         nodeDto.setAddress(nodeId.getApiAddress());
4277         nodeDto.setApiPort(nodeId.getApiPort());
4278         nodeDto.setStatus(status.getState().name());
4279         nodeDto.setRoles(roles);
4280         if (status.getConnectionRequestTime() != null) {
4281             final Date connectionRequested = new Date(status.getConnectionRequestTime());
4282             nodeDto.setConnectionRequested(connectionRequested);
4283         }
4284
4285         // only connected nodes have heartbeats
4286         if (nodeHeartbeat != null) {
4287             final Date heartbeat = new Date(nodeHeartbeat.getTimestamp());
4288             nodeDto.setHeartbeat(heartbeat);
4289             nodeDto.setNodeStartTime(new Date(nodeHeartbeat.getSystemStartTime()));
4290             nodeDto.setActiveThreadCount(nodeHeartbeat.getActiveThreadCount());
4291             nodeDto.setQueued(FormatUtils.formatCount(nodeHeartbeat.getFlowFileCount()) + " / " + FormatUtils.formatDataSize(nodeHeartbeat.getFlowFileBytes()));
4292         }
4293
4294         // populate node events
4295         final List<NodeEvent> nodeEvents = new ArrayList<>(events);
4296         Collections.sort(nodeEvents, new Comparator<NodeEvent>() {
4297             @Override
4298             public int compare(final NodeEvent event1, final NodeEvent event2) {
4299                 return new Date(event2.getTimestamp()).compareTo(new Date(event1.getTimestamp()));
4300             }
4301         });
4302
4303         // create the node event dtos
4304         final List<NodeEventDTO> nodeEventDtos = new ArrayList<>();
4305         for (final NodeEvent event : nodeEvents) {
4306             // create node event dto
4307             final NodeEventDTO nodeEventDto = new NodeEventDTO();
4308             nodeEventDtos.add(nodeEventDto);
4309
4310             // populate node event dto
4311             nodeEventDto.setMessage(event.getMessage());
4312             nodeEventDto.setCategory(event.getSeverity().name());
4313             nodeEventDto.setTimestamp(new Date(event.getTimestamp()));
4314         }
4315         nodeDto.setEvents(nodeEventDtos);
4316
4317         return nodeDto;
4318     }
4319
4320     public RegistryDTO createRegistryDto(FlowRegistry registry) {
4321         final RegistryDTO dto = new RegistryDTO();
4322         dto.setDescription(registry.getDescription());
4323         dto.setId(registry.getIdentifier());
4324         dto.setName(registry.getName());
4325         dto.setUri(registry.getURL());
4326         return dto;
4327     }
4328
4329
4330     /* setters */
4331     public void setControllerServiceProvider(final ControllerServiceProvider controllerServiceProvider) {
4332         this.controllerServiceProvider = controllerServiceProvider;
4333     }
4334
4335     public void setAuthorizer(final Authorizer authorizer) {
4336         this.authorizer = authorizer;
4337     }
4338
4339     public void setEntityFactory(final EntityFactory entityFactory) {
4340         this.entityFactory = entityFactory;
4341     }
4342
4343     public void setBulletinRepository(BulletinRepository bulletinRepository) {
4344         this.bulletinRepository = bulletinRepository;
4345     }
4346
4347     public void setExtensionManager(ExtensionManager extensionManager) {
4348         this.extensionManager = extensionManager;
4349     }
4350 }