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.io.File; 022import java.nio.file.Files; 023import java.nio.file.Path; 024import java.util.List; 025 026import org.eclipse.aether.ConfigurationProperties; 027import org.eclipse.aether.RepositorySystemSession; 028import org.eclipse.aether.artifact.Artifact; 029import org.eclipse.aether.metadata.Metadata; 030import org.eclipse.aether.repository.LocalArtifactRegistration; 031import org.eclipse.aether.repository.LocalArtifactRequest; 032import org.eclipse.aether.repository.LocalArtifactResult; 033import org.eclipse.aether.repository.LocalMetadataRegistration; 034import org.eclipse.aether.repository.LocalMetadataRequest; 035import org.eclipse.aether.repository.LocalMetadataResult; 036import org.eclipse.aether.repository.LocalRepository; 037import org.eclipse.aether.repository.LocalRepositoryManager; 038import org.eclipse.aether.repository.RemoteRepository; 039import org.eclipse.aether.util.ConfigUtils; 040 041import static java.util.Objects.requireNonNull; 042import static java.util.stream.Collectors.toList; 043 044/** 045 * A local repository manager that chains multiple local repository managers: it directs all the write operations 046 * to chain head, while uses tail for {@link #find(RepositorySystemSession, LocalArtifactRequest)} and 047 * {@link #find(RepositorySystemSession, LocalMetadataRequest)} methods only. Hence, tail is used in resolving 048 * metadata and artifacts with or without (configurable) artifact availability tracking. 049 * <p> 050 * Implementation represents itself using the head local repository manager. 051 * 052 * @since 1.9.2 053 */ 054public final class ChainedLocalRepositoryManager implements LocalRepositoryManager { 055 private static final String CONFIG_PROPS_PREFIX = ConfigurationProperties.PREFIX_AETHER + "chainedLocalRepository."; 056 057 /** 058 * When using chained local repository, should be the artifact availability ignored in tail. 059 * 060 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 061 * @configurationType {@link java.lang.Boolean} 062 * @configurationDefaultValue {@link #DEFAULT_IGNORE_TAIL_AVAILABILITY} 063 */ 064 public static final String CONFIG_PROP_IGNORE_TAIL_AVAILABILITY = CONFIG_PROPS_PREFIX + "ignoreTailAvailability"; 065 066 public static final boolean DEFAULT_IGNORE_TAIL_AVAILABILITY = true; 067 068 private final LocalRepositoryManager head; 069 070 private final List<LocalRepositoryManager> tail; 071 072 private final boolean ignoreTailAvailability; 073 074 public ChainedLocalRepositoryManager( 075 LocalRepositoryManager head, List<LocalRepositoryManager> tail, boolean ignoreTailAvailability) { 076 this.head = requireNonNull(head, "head cannot be null"); 077 this.tail = requireNonNull(tail, "tail cannot be null"); 078 this.ignoreTailAvailability = ignoreTailAvailability; 079 } 080 081 public ChainedLocalRepositoryManager( 082 LocalRepositoryManager head, List<LocalRepositoryManager> tail, RepositorySystemSession session) { 083 this.head = requireNonNull(head, "head cannot be null"); 084 this.tail = requireNonNull(tail, "tail cannot be null"); 085 this.ignoreTailAvailability = 086 ConfigUtils.getBoolean(session, DEFAULT_IGNORE_TAIL_AVAILABILITY, CONFIG_PROP_IGNORE_TAIL_AVAILABILITY); 087 } 088 089 @Override 090 public LocalRepository getRepository() { 091 return head.getRepository(); 092 } 093 094 @Override 095 public String getPathForLocalArtifact(Artifact artifact) { 096 return head.getPathForLocalArtifact(artifact); 097 } 098 099 @Override 100 public String getPathForRemoteArtifact(Artifact artifact, RemoteRepository repository, String context) { 101 return head.getPathForRemoteArtifact(artifact, repository, context); 102 } 103 104 @Override 105 public String getPathForLocalMetadata(Metadata metadata) { 106 return head.getPathForLocalMetadata(metadata); 107 } 108 109 @Override 110 public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repository, String context) { 111 return head.getPathForRemoteMetadata(metadata, repository, context); 112 } 113 114 @Override 115 public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRequest request) { 116 LocalArtifactResult result = head.find(session, request); 117 if (result.isAvailable()) { 118 return result; 119 } 120 121 for (LocalRepositoryManager lrm : tail) { 122 result = lrm.find(session, request); 123 if (result.getFile() != null) { 124 if (ignoreTailAvailability) { 125 result.setAvailable(true); 126 return result; 127 } else if (result.isAvailable()) { 128 return result; 129 } 130 } 131 } 132 return new LocalArtifactResult(request); 133 } 134 135 @Override 136 public void add(RepositorySystemSession session, LocalArtifactRegistration request) { 137 String artifactPath; 138 if (request.getRepository() != null) { 139 artifactPath = getPathForRemoteArtifact(request.getArtifact(), request.getRepository(), "check"); 140 } else { 141 artifactPath = getPathForLocalArtifact(request.getArtifact()); 142 } 143 144 Path file = new File(head.getRepository().getBasedir(), artifactPath).toPath(); 145 if (Files.isRegularFile(file)) { 146 head.add(session, request); 147 } 148 } 149 150 @Override 151 public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRequest request) { 152 LocalMetadataResult result = head.find(session, request); 153 if (result.getFile() != null) { 154 return result; 155 } 156 157 for (LocalRepositoryManager lrm : tail) { 158 result = lrm.find(session, request); 159 if (result.getFile() != null) { 160 return result; 161 } 162 } 163 return new LocalMetadataResult(request); 164 } 165 166 @Override 167 public void add(RepositorySystemSession session, LocalMetadataRegistration request) { 168 String metadataPath; 169 if (request.getRepository() != null) { 170 metadataPath = getPathForRemoteMetadata(request.getMetadata(), request.getRepository(), "check"); 171 } else { 172 metadataPath = getPathForLocalMetadata(request.getMetadata()); 173 } 174 175 Path file = new File(head.getRepository().getBasedir(), metadataPath).toPath(); 176 if (Files.isRegularFile(file)) { 177 head.add(session, request); 178 } 179 } 180 181 @Override 182 public String toString() { 183 return head.getRepository().toString() 184 + tail.stream().map(LocalRepositoryManager::getRepository).collect(toList()); 185 } 186}