2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.packaging
.impl
.artifacts
;
18 import com
.intellij
.openapi
.application
.ApplicationManager
;
19 import com
.intellij
.openapi
.application
.Result
;
20 import com
.intellij
.openapi
.application
.WriteAction
;
21 import com
.intellij
.openapi
.components
.*;
22 import com
.intellij
.openapi
.diagnostic
.Logger
;
23 import com
.intellij
.openapi
.project
.Project
;
24 import com
.intellij
.openapi
.util
.ModificationTracker
;
25 import com
.intellij
.openapi
.util
.Pair
;
26 import com
.intellij
.openapi
.vfs
.*;
27 import com
.intellij
.packaging
.artifacts
.*;
28 import com
.intellij
.packaging
.elements
.*;
29 import com
.intellij
.util
.containers
.ContainerUtil
;
30 import com
.intellij
.util
.xmlb
.SkipDefaultValuesSerializationFilters
;
31 import com
.intellij
.util
.xmlb
.XmlSerializer
;
32 import gnu
.trove
.THashSet
;
33 import org
.jdom
.Element
;
34 import org
.jetbrains
.annotations
.NonNls
;
35 import org
.jetbrains
.annotations
.NotNull
;
36 import org
.jetbrains
.annotations
.Nullable
;
44 name
= ArtifactManagerImpl
.COMPONENT_NAME
,
46 @Storage(id
= "other", file
= "$PROJECT_FILE$"),
47 @Storage(id
= "dir", file
= "$PROJECT_CONFIG_DIR$/artifacts/", scheme
= StorageScheme
.DIRECTORY_BASED
, stateSplitter
= ArtifactManagerStateSplitter
.class)
50 public class ArtifactManagerImpl
extends ArtifactManager
implements ProjectComponent
, PersistentStateComponent
<ArtifactManagerState
> {
51 private static final Logger LOG
= Logger
.getInstance("#com.intellij.packaging.impl.artifacts.ArtifactManagerImpl");
52 @NonNls public static final String COMPONENT_NAME
= "ArtifactManager";
53 @NonNls public static final String PACKAGING_ELEMENT_NAME
= "element";
54 @NonNls public static final String TYPE_ID_ATTRIBUTE
= "id";
55 private final ArtifactManagerModel myModel
= new ArtifactManagerModel();
56 private final Project myProject
;
57 private final DefaultPackagingElementResolvingContext myResolvingContext
;
58 private boolean myInsideCommit
= false;
59 private boolean myLoaded
;
60 private long myModificationCount
;
61 private final ModificationTracker myModificationTracker
= new ModificationTracker() {
62 public long getModificationCount() {
63 return myModificationCount
;
66 private Map
<String
, LocalFileSystem
.WatchRequest
> myWatchedOutputs
= new HashMap
<String
, LocalFileSystem
.WatchRequest
>();
68 public ArtifactManagerImpl(Project project
, VirtualFileManager virtualFileManager
) {
70 myResolvingContext
= new DefaultPackagingElementResolvingContext(myProject
);
71 virtualFileManager
.addVirtualFileListener(new ArtifactVirtualFileListener(myProject
, this), myProject
);
75 public Artifact
[] getArtifacts() {
76 return myModel
.getArtifacts();
79 public Artifact
findArtifact(@NotNull String name
) {
80 return myModel
.findArtifact(name
);
84 public Artifact
getArtifactByOriginal(@NotNull Artifact artifact
) {
85 return myModel
.getArtifactByOriginal(artifact
);
88 public Collection
<?
extends Artifact
> getArtifactsByType(@NotNull ArtifactType type
) {
89 return myModel
.getArtifactsByType(type
);
92 public ArtifactManagerState
getState() {
93 final ArtifactManagerState state
= new ArtifactManagerState();
94 for (Artifact artifact
: getArtifacts()) {
95 final ArtifactState artifactState
= new ArtifactState();
96 artifactState
.setBuildOnMake(artifact
.isBuildOnMake());
97 artifactState
.setName(artifact
.getName());
98 artifactState
.setOutputPath(artifact
.getOutputPath());
99 artifactState
.setRootElement(serializePackagingElement(artifact
.getRootElement()));
100 artifactState
.setArtifactType(artifact
.getArtifactType().getId());
101 for (ArtifactPropertiesProvider provider
: artifact
.getPropertiesProviders()) {
102 final ArtifactPropertiesState propertiesState
= serializeProperties(provider
, artifact
.getProperties(provider
));
103 if (propertiesState
!= null) {
104 artifactState
.getPropertiesList().add(propertiesState
);
107 state
.getArtifacts().add(artifactState
);
113 private static <S
> ArtifactPropertiesState
serializeProperties(ArtifactPropertiesProvider provider
, ArtifactProperties
<S
> properties
) {
114 final ArtifactPropertiesState state
= new ArtifactPropertiesState();
115 state
.setId(provider
.getId());
116 final Element options
= new Element("options");
117 XmlSerializer
.serializeInto(properties
.getState(), options
, new SkipDefaultValuesSerializationFilters());
118 if (options
.getContent().isEmpty() && options
.getAttributes().isEmpty()) return null;
119 state
.setOptions(options
);
123 private static Element
serializePackagingElement(PackagingElement
<?
> packagingElement
) {
124 Element element
= new Element(PACKAGING_ELEMENT_NAME
);
125 element
.setAttribute(TYPE_ID_ATTRIBUTE
, packagingElement
.getType().getId());
126 final Object bean
= packagingElement
.getState();
128 XmlSerializer
.serializeInto(bean
, element
, new SkipDefaultValuesSerializationFilters());
130 if (packagingElement
instanceof CompositePackagingElement
) {
131 for (PackagingElement
<?
> child
: ((CompositePackagingElement
<?
>)packagingElement
).getChildren()) {
132 element
.addContent(serializePackagingElement(child
));
138 private <T
> PackagingElement
<T
> deserializeElement(Element element
) {
139 final String id
= element
.getAttributeValue(TYPE_ID_ATTRIBUTE
);
140 PackagingElementType
<?
> type
= PackagingElementFactory
.getInstance().findElementType(id
);
141 PackagingElement
<T
> packagingElement
= (PackagingElement
<T
>)type
.createEmpty(myProject
);
142 T state
= packagingElement
.getState();
144 XmlSerializer
.deserializeInto(state
, element
);
145 packagingElement
.loadState(state
);
147 final List children
= element
.getChildren(PACKAGING_ELEMENT_NAME
);
148 //noinspection unchecked
149 for (Element child
: (List
<?
extends Element
>)children
) {
150 ((CompositePackagingElement
<?
>)packagingElement
).addOrFindChild(deserializeElement(child
));
152 return packagingElement
;
155 public void loadState(ArtifactManagerState managerState
) {
156 final List
<ArtifactImpl
> artifacts
= new ArrayList
<ArtifactImpl
>();
157 for (ArtifactState state
: managerState
.getArtifacts()) {
158 final Element element
= state
.getRootElement();
159 ArtifactType type
= ArtifactType
.findById(state
.getArtifactType());
161 LOG
.info("Unknown artifact type: " + state
.getArtifactType());
165 final String artifactName
= state
.getName();
166 final CompositePackagingElement
<?
> rootElement
;
167 if (element
!= null) {
168 rootElement
= (CompositePackagingElement
<?
>)deserializeElement(element
);
171 rootElement
= type
.createRootElement(artifactName
);
174 final ArtifactImpl artifact
= new ArtifactImpl(artifactName
, type
, state
.isBuildOnMake(), rootElement
, state
.getOutputPath());
175 final List
<ArtifactPropertiesState
> propertiesList
= state
.getPropertiesList();
176 for (ArtifactPropertiesState propertiesState
: propertiesList
) {
177 final ArtifactPropertiesProvider provider
= ArtifactPropertiesProvider
.findById(propertiesState
.getId());
178 if (provider
!= null) {
179 deserializeProperties(artifact
.getProperties(provider
), propertiesState
);
182 artifacts
.add(artifact
);
186 final ArtifactModelImpl model
= new ArtifactModelImpl(this);
187 model
.addArtifacts(artifacts
);
191 myModel
.setArtifactsList(artifacts
);
196 private static <S
> void deserializeProperties(ArtifactProperties
<S
> artifactProperties
, ArtifactPropertiesState propertiesState
) {
197 final Element options
= propertiesState
.getOptions();
198 if (artifactProperties
== null || options
== null) {
201 final S state
= artifactProperties
.getState();
203 XmlSerializer
.deserializeInto(state
, options
);
204 artifactProperties
.loadState(state
);
208 public void disposeComponent() {
209 LocalFileSystem
.getInstance().removeWatchedRoots(myWatchedOutputs
.values());
213 public String
getComponentName() {
214 return COMPONENT_NAME
;
217 public void initComponent() {
218 updateWatchedRoots();
221 private void updateWatchedRoots() {
222 Set
<String
> pathsToRemove
= new HashSet
<String
>(myWatchedOutputs
.keySet());
223 Set
<String
> toAdd
= new HashSet
<String
>();
224 for (Artifact artifact
: getArtifacts()) {
225 final String path
= artifact
.getOutputPath();
226 if (path
!= null && path
.length() > 0) {
227 pathsToRemove
.remove(path
);
228 if (!myWatchedOutputs
.containsKey(path
)) {
234 List
<LocalFileSystem
.WatchRequest
> requestsToRemove
= new ArrayList
<LocalFileSystem
.WatchRequest
>();
235 for (String path
: pathsToRemove
) {
236 final LocalFileSystem
.WatchRequest request
= myWatchedOutputs
.remove(path
);
237 ContainerUtil
.addIfNotNull(request
, requestsToRemove
);
240 final LocalFileSystem fileSystem
= LocalFileSystem
.getInstance();
241 fileSystem
.removeWatchedRoots(requestsToRemove
);
242 final Set
<LocalFileSystem
.WatchRequest
> newRequests
= fileSystem
.addRootsToWatch(toAdd
, true);
243 for (LocalFileSystem
.WatchRequest request
: newRequests
) {
244 myWatchedOutputs
.put(request
.getRootPath(), request
);
248 public void projectOpened() {
251 public void projectClosed() {
255 public Artifact
[] getSortedArtifacts() {
256 return myModel
.getSortedArtifacts();
260 public ModifiableArtifactModel
createModifiableModel() {
261 ((ArtifactPointerManagerImpl
)ArtifactPointerManager
.getInstance(myProject
)).updateAllPointers();
262 final ArtifactModelImpl model
= new ArtifactModelImpl(this);
263 model
.addArtifacts(getArtifactsList());
268 public PackagingElementResolvingContext
getResolvingContext() {
269 return myResolvingContext
;
272 public List
<ArtifactImpl
> getArtifactsList() {
273 return myModel
.myArtifactsList
;
276 public void commit(ArtifactModelImpl artifactModel
) {
277 ApplicationManager
.getApplication().assertWriteAccessAllowed();
279 doCommit(artifactModel
);
282 private void doCommit(ArtifactModelImpl artifactModel
) {
283 LOG
.assertTrue(!myInsideCommit
, "Recursive commit");
284 myInsideCommit
= true;
287 final List
<ArtifactImpl
> allArtifacts
= artifactModel
.getOriginalArtifacts();
289 Set
<ArtifactImpl
> removed
= new THashSet
<ArtifactImpl
>(myModel
.myArtifactsList
);
290 List
<ArtifactImpl
> added
= new ArrayList
<ArtifactImpl
>();
291 List
<Pair
<ArtifactImpl
, String
>> changed
= new ArrayList
<Pair
<ArtifactImpl
, String
>>();
293 for (ArtifactImpl artifact
: allArtifacts
) {
294 final boolean isAdded
= !removed
.remove(artifact
);
295 final ArtifactImpl modifiableCopy
= artifactModel
.getModifiableCopy(artifact
);
299 else if (modifiableCopy
!= null && !modifiableCopy
.equals(artifact
)) {
300 final String oldName
= artifact
.getName();
301 artifact
.copyFrom(modifiableCopy
);
302 changed
.add(Pair
.create(artifact
, oldName
));
306 myModel
.setArtifactsList(allArtifacts
);
307 myModificationCount
++;
308 final ArtifactListener publisher
= myProject
.getMessageBus().syncPublisher(TOPIC
);
309 for (ArtifactImpl artifact
: added
) {
310 publisher
.artifactAdded(artifact
);
312 for (ArtifactImpl artifact
: removed
) {
313 publisher
.artifactRemoved(artifact
);
315 for (Pair
<ArtifactImpl
, String
> pair
: changed
) {
316 publisher
.artifactChanged(pair
.getFirst(), pair
.getSecond());
320 myInsideCommit
= false;
324 public Project
getProject() {
329 public Artifact
addArtifact(@NotNull final String name
, @NotNull final ArtifactType type
, final CompositePackagingElement
<?
> root
) {
330 return new WriteAction
<Artifact
>() {
331 protected void run(final Result
<Artifact
> result
) {
332 final ModifiableArtifactModel model
= createModifiableModel();
333 final ModifiableArtifact artifact
= model
.addArtifact(name
, type
);
335 artifact
.setRootElement(root
);
338 result
.setResult(artifact
);
340 }.execute().getResultObject();
344 public void addElementsToDirectory(@NotNull Artifact artifact
, @NotNull String relativePath
, @NotNull PackagingElement
<?
> element
) {
345 addElementsToDirectory(artifact
, relativePath
, Collections
.singletonList(element
));
349 public void addElementsToDirectory(@NotNull Artifact artifact
, @NotNull String relativePath
,
350 @NotNull Collection
<?
extends PackagingElement
<?
>> elements
) {
351 final ModifiableArtifactModel model
= createModifiableModel();
352 final CompositePackagingElement
<?
> root
= model
.getOrCreateModifiableArtifact(artifact
).getRootElement();
353 PackagingElementFactory
.getInstance().getOrCreateDirectory(root
, relativePath
).addOrFindChildren(elements
);
355 protected void run(final Result result
) {
362 public ModificationTracker
getModificationTracker() {
363 return myModificationTracker
;
366 private static class ArtifactManagerModel
extends ArtifactModelBase
{
367 private List
<ArtifactImpl
> myArtifactsList
= new ArrayList
<ArtifactImpl
>();
368 private Artifact
[] mySortedArtifacts
;
370 public void setArtifactsList(List
<ArtifactImpl
> artifactsList
) {
371 myArtifactsList
= artifactsList
;
376 protected void artifactsChanged() {
377 super.artifactsChanged();
378 mySortedArtifacts
= null;
381 protected List
<?
extends Artifact
> getArtifactsList() {
382 return myArtifactsList
;
385 public Artifact
[] getSortedArtifacts() {
386 if (mySortedArtifacts
== null) {
387 mySortedArtifacts
= getArtifacts().clone();
388 Arrays
.sort(mySortedArtifacts
, ARTIFACT_COMPARATOR
);
390 return mySortedArtifacts
;