001package org.eclipse.aether.util.repository;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 * 
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 * 
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.File;
023import java.util.ArrayList;
024import java.util.Collection;
025import java.util.Collections;
026import java.util.LinkedHashSet;
027import java.util.List;
028
029import org.eclipse.aether.artifact.Artifact;
030import org.eclipse.aether.repository.WorkspaceReader;
031import org.eclipse.aether.repository.WorkspaceRepository;
032
033import static java.util.Objects.requireNonNull;
034
035/**
036 * A workspace reader that delegates to a chain of other readers, effectively aggregating their contents.
037 */
038public final class ChainedWorkspaceReader
039    implements WorkspaceReader
040{
041
042    private final List<WorkspaceReader> readers = new ArrayList<>();
043
044    private WorkspaceRepository repository;
045
046    /**
047     * Creates a new workspace reader by chaining the specified readers.
048     * 
049     * @param readers The readers to chain, may be {@code null}.
050     * @see #newInstance(WorkspaceReader, WorkspaceReader)
051     */
052    public ChainedWorkspaceReader( WorkspaceReader... readers )
053    {
054        if ( readers != null )
055        {
056            Collections.addAll( this.readers, readers );
057        }
058
059        StringBuilder buffer = new StringBuilder();
060        for ( WorkspaceReader reader : this.readers )
061        {
062            if ( buffer.length() > 0 )
063            {
064                buffer.append( '+' );
065            }
066            buffer.append( reader.getRepository().getContentType() );
067        }
068
069        repository = new WorkspaceRepository( buffer.toString(), new Key( this.readers ) );
070    }
071
072    /**
073     * Creates a new workspace reader by chaining the specified readers. In contrast to the constructor, this factory
074     * method will avoid creating an actual chained reader if one of the specified readers is actually {@code null}.
075     * 
076     * @param reader1 The first workspace reader, may be {@code null}.
077     * @param reader2 The second workspace reader, may be {@code null}.
078     * @return The chained reader or {@code null} if no workspace reader was supplied.
079     */
080    public static WorkspaceReader newInstance( WorkspaceReader reader1, WorkspaceReader reader2 )
081    {
082        if ( reader1 == null )
083        {
084            return reader2;
085        }
086        else if ( reader2 == null )
087        {
088            return reader1;
089        }
090        return new ChainedWorkspaceReader( reader1, reader2 );
091    }
092
093    public File findArtifact( Artifact artifact )
094    {
095        requireNonNull( artifact, "artifact cannot be null" );
096        File file = null;
097
098        for ( WorkspaceReader reader : readers )
099        {
100            file = reader.findArtifact( artifact );
101            if ( file != null )
102            {
103                break;
104            }
105        }
106
107        return file;
108    }
109
110    public List<String> findVersions( Artifact artifact )
111    {
112        requireNonNull( artifact, "artifact cannot be null" );
113        Collection<String> versions = new LinkedHashSet<>();
114
115        for ( WorkspaceReader reader : readers )
116        {
117            versions.addAll( reader.findVersions( artifact ) );
118        }
119
120        return Collections.unmodifiableList( new ArrayList<>( versions ) );
121    }
122
123    public WorkspaceRepository getRepository()
124    {
125        Key key = new Key( readers );
126        if ( !key.equals( repository.getKey() ) )
127        {
128            repository = new WorkspaceRepository( repository.getContentType(), key );
129        }
130        return repository;
131    }
132
133    private static class Key
134    {
135
136        private final List<Object> keys = new ArrayList<>();
137
138        Key( List<WorkspaceReader> readers )
139        {
140            for ( WorkspaceReader reader : readers )
141            {
142                keys.add( reader.getRepository().getKey() );
143            }
144        }
145
146        @Override
147        public boolean equals( Object obj )
148        {
149            if ( this == obj )
150            {
151                return true;
152            }
153            if ( obj == null || !getClass().equals( obj.getClass() ) )
154            {
155                return false;
156            }
157            return keys.equals( ( (Key) obj ).keys );
158        }
159
160        @Override
161        public int hashCode()
162        {
163            return keys.hashCode();
164        }
165
166    }
167
168}