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