001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.util.repository; 020 021import java.nio.file.Files; 022import java.nio.file.Path; 023import java.util.List; 024 025import org.eclipse.aether.ConfigurationProperties; 026import org.eclipse.aether.RepositorySystemSession; 027import org.eclipse.aether.artifact.Artifact; 028import org.eclipse.aether.metadata.Metadata; 029import org.eclipse.aether.repository.LocalArtifactRegistration; 030import org.eclipse.aether.repository.LocalArtifactRequest; 031import org.eclipse.aether.repository.LocalArtifactResult; 032import org.eclipse.aether.repository.LocalMetadataRegistration; 033import org.eclipse.aether.repository.LocalMetadataRequest; 034import org.eclipse.aether.repository.LocalMetadataResult; 035import org.eclipse.aether.repository.LocalRepository; 036import org.eclipse.aether.repository.LocalRepositoryManager; 037import org.eclipse.aether.repository.RemoteRepository; 038import org.eclipse.aether.util.ConfigUtils; 039 040import static java.util.Objects.requireNonNull; 041import static java.util.stream.Collectors.toList; 042 043/** 044 * A local repository manager that chains multiple local repository managers: it directs all the write operations 045 * to chain head, while uses tail for {@link #find(RepositorySystemSession, LocalArtifactRequest)} and 046 * {@link #find(RepositorySystemSession, LocalMetadataRequest)} methods only. Hence, tail is used in resolving 047 * metadata and artifacts with or without (configurable) artifact availability tracking. 048 * <p> 049 * Implementation represents itself using the head local repository manager. 050 * 051 * @since 1.9.2 052 */ 053public final class ChainedLocalRepositoryManager implements LocalRepositoryManager { 054 private static final String CONFIG_PROPS_PREFIX = ConfigurationProperties.PREFIX_AETHER + "chainedLocalRepository."; 055 056 /** 057 * When using chained local repository, should be the artifact availability ignored in tail. 058 * 059 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 060 * @configurationType {@link java.lang.Boolean} 061 * @configurationDefaultValue {@link #DEFAULT_IGNORE_TAIL_AVAILABILITY} 062 */ 063 public static final String CONFIG_PROP_IGNORE_TAIL_AVAILABILITY = CONFIG_PROPS_PREFIX + "ignoreTailAvailability"; 064 065 public static final boolean DEFAULT_IGNORE_TAIL_AVAILABILITY = true; 066 067 private final LocalRepositoryManager head; 068 069 private final List<LocalRepositoryManager> tail; 070 071 private final boolean ignoreTailAvailability; 072 073 public ChainedLocalRepositoryManager( 074 LocalRepositoryManager head, List<LocalRepositoryManager> tail, boolean ignoreTailAvailability) { 075 this.head = requireNonNull(head, "head cannot be null"); 076 this.tail = requireNonNull(tail, "tail cannot be null"); 077 this.ignoreTailAvailability = ignoreTailAvailability; 078 } 079 080 public ChainedLocalRepositoryManager( 081 LocalRepositoryManager head, List<LocalRepositoryManager> tail, RepositorySystemSession session) { 082 this.head = requireNonNull(head, "head cannot be null"); 083 this.tail = requireNonNull(tail, "tail cannot be null"); 084 this.ignoreTailAvailability = 085 ConfigUtils.getBoolean(session, DEFAULT_IGNORE_TAIL_AVAILABILITY, CONFIG_PROP_IGNORE_TAIL_AVAILABILITY); 086 } 087 088 @Override 089 public LocalRepository getRepository() { 090 return head.getRepository(); 091 } 092 093 @Override 094 public String getPathForLocalArtifact(Artifact artifact) { 095 return head.getPathForLocalArtifact(artifact); 096 } 097 098 @Override 099 public String getPathForRemoteArtifact(Artifact artifact, RemoteRepository repository, String context) { 100 return head.getPathForRemoteArtifact(artifact, repository, context); 101 } 102 103 @Override 104 public String getPathForLocalMetadata(Metadata metadata) { 105 return head.getPathForLocalMetadata(metadata); 106 } 107 108 @Override 109 public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repository, String context) { 110 return head.getPathForRemoteMetadata(metadata, repository, context); 111 } 112 113 @Override 114 public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRequest request) { 115 LocalArtifactResult result = head.find(session, request); 116 if (result.isAvailable()) { 117 return result; 118 } 119 120 for (LocalRepositoryManager lrm : tail) { 121 result = lrm.find(session, request); 122 if (result.getPath() != null) { 123 if (ignoreTailAvailability) { 124 result.setAvailable(true); 125 return result; 126 } else if (result.isAvailable()) { 127 return result; 128 } 129 } 130 } 131 return new LocalArtifactResult(request); 132 } 133 134 @Override 135 public void add(RepositorySystemSession session, LocalArtifactRegistration request) { 136 String artifactPath; 137 if (request.getRepository() != null) { 138 artifactPath = getPathForRemoteArtifact(request.getArtifact(), request.getRepository(), "check"); 139 } else { 140 artifactPath = getPathForLocalArtifact(request.getArtifact()); 141 } 142 143 Path file = head.getRepository().getBasePath().resolve(artifactPath); 144 if (Files.isRegularFile(file)) { 145 head.add(session, request); 146 } 147 } 148 149 @Override 150 public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRequest request) { 151 LocalMetadataResult result = head.find(session, request); 152 if (result.getPath() != null) { 153 return result; 154 } 155 156 for (LocalRepositoryManager lrm : tail) { 157 result = lrm.find(session, request); 158 if (result.getPath() != null) { 159 return result; 160 } 161 } 162 return new LocalMetadataResult(request); 163 } 164 165 @Override 166 public void add(RepositorySystemSession session, LocalMetadataRegistration request) { 167 String metadataPath; 168 if (request.getRepository() != null) { 169 metadataPath = getPathForRemoteMetadata(request.getMetadata(), request.getRepository(), "check"); 170 } else { 171 metadataPath = getPathForLocalMetadata(request.getMetadata()); 172 } 173 174 Path file = head.getRepository().getBasePath().resolve(metadataPath); 175 if (Files.isRegularFile(file)) { 176 head.add(session, request); 177 } 178 } 179 180 @Override 181 public String toString() { 182 return head.getRepository().toString() 183 + tail.stream().map(LocalRepositoryManager::getRepository).collect(toList()); 184 } 185}