001    package org.apache.archiva.rest.services;
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    
022    import org.apache.archiva.admin.model.AuditInformation;
023    import org.apache.archiva.admin.model.RepositoryAdminException;
024    import org.apache.archiva.admin.model.admin.ArchivaAdministration;
025    import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
026    import org.apache.archiva.audit.AuditEvent;
027    import org.apache.archiva.audit.AuditListener;
028    import org.apache.archiva.common.utils.VersionUtil;
029    import org.apache.archiva.maven2.model.Artifact;
030    import org.apache.archiva.metadata.model.ArtifactMetadata;
031    import org.apache.archiva.metadata.repository.RepositorySessionFactory;
032    import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
033    import org.apache.archiva.redback.configuration.UserConfiguration;
034    import org.apache.archiva.redback.configuration.UserConfigurationKeys;
035    import org.apache.archiva.redback.rest.services.RedbackAuthenticationThreadLocal;
036    import org.apache.archiva.redback.rest.services.RedbackRequestInformation;
037    import org.apache.archiva.redback.users.User;
038    import org.apache.archiva.repository.RepositoryContentFactory;
039    import org.apache.archiva.repository.RepositoryException;
040    import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
041    import org.apache.archiva.rest.services.utils.ArtifactBuilder;
042    import org.apache.archiva.scheduler.repository.DefaultRepositoryArchivaTaskScheduler;
043    import org.apache.archiva.scheduler.repository.model.RepositoryTask;
044    import org.apache.archiva.security.AccessDeniedException;
045    import org.apache.archiva.security.ArchivaSecurityException;
046    import org.apache.archiva.security.PrincipalNotFoundException;
047    import org.apache.archiva.security.UserRepositories;
048    import org.apache.commons.lang.StringUtils;
049    import org.slf4j.Logger;
050    import org.slf4j.LoggerFactory;
051    import org.springframework.context.ApplicationContext;
052    
053    import javax.inject.Inject;
054    import javax.inject.Named;
055    import javax.servlet.http.HttpServletRequest;
056    import javax.ws.rs.core.Context;
057    import javax.ws.rs.core.Response;
058    import java.util.ArrayList;
059    import java.util.Collections;
060    import java.util.HashMap;
061    import java.util.List;
062    import java.util.Map;
063    
064    /**
065     * abstract class with common utilities methods
066     *
067     * @author Olivier Lamy
068     * @since 1.4-M1
069     */
070    public abstract class AbstractRestService
071    {
072    
073        protected Logger log = LoggerFactory.getLogger( getClass() );
074    
075        @Inject
076        private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
077    
078        @Inject
079        protected UserRepositories userRepositories;
080    
081    
082        /**
083         * FIXME: this could be multiple implementations and needs to be configured.
084         */
085        @Inject
086        @Named(value = "repositorySessionFactory")
087        protected RepositorySessionFactory repositorySessionFactory;
088    
089        @Inject
090        protected ArchivaAdministration archivaAdministration;
091    
092        @Inject
093        protected ManagedRepositoryAdmin managedRepositoryAdmin;
094    
095        @Inject
096        protected RepositoryContentFactory repositoryContentFactory;
097    
098        @Inject
099        @Named(value = "archivaTaskScheduler#repository")
100        protected DefaultRepositoryArchivaTaskScheduler repositoryTaskScheduler;
101    
102    
103        @Inject
104        @Named( value = "userConfiguration#default" )
105        protected UserConfiguration config;
106    
107        @Context
108        protected HttpServletRequest httpServletRequest;
109    
110        protected AuditInformation getAuditInformation()
111        {
112            RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get();
113            User user = redbackRequestInformation == null ? null : redbackRequestInformation.getUser();
114            String remoteAddr = redbackRequestInformation == null ? null : redbackRequestInformation.getRemoteAddr();
115            return new AuditInformation( user, remoteAddr );
116        }
117    
118        public List<AuditListener> getAuditListeners()
119        {
120            return auditListeners;
121        }
122    
123        public void setAuditListeners( List<AuditListener> auditListeners )
124        {
125            this.auditListeners = auditListeners;
126        }
127    
128        protected List<String> getObservableRepos()
129        {
130            try
131            {
132                List<String> ids = userRepositories.getObservableRepositoryIds( getPrincipal() );
133                return ids == null ? Collections.<String>emptyList() : ids;
134            }
135            catch ( PrincipalNotFoundException e )
136            {
137                log.warn( e.getMessage(), e );
138            }
139            catch ( AccessDeniedException e )
140            {
141                log.warn( e.getMessage(), e );
142            }
143            catch ( ArchivaSecurityException e )
144            {
145                log.warn( e.getMessage(), e );
146            }
147            return Collections.emptyList();
148        }
149    
150        protected String getPrincipal()
151        {
152            RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get();
153    
154            return redbackRequestInformation == null
155                ? config.getString( UserConfigurationKeys.DEFAULT_GUEST )
156                : ( redbackRequestInformation.getUser() == null
157                    ? config.getString( UserConfigurationKeys.DEFAULT_GUEST )
158                    : redbackRequestInformation.getUser().getUsername() );
159        }
160    
161        protected String getBaseUrl()
162            throws RepositoryAdminException
163        {
164            String applicationUrl = archivaAdministration.getUiConfiguration().getApplicationUrl();
165            if ( StringUtils.isNotBlank( applicationUrl ) )
166            {
167                return applicationUrl;
168            }
169            return httpServletRequest.getScheme() + "://" + httpServletRequest.getServerName() + (
170                httpServletRequest.getServerPort() == 80 ? "" : ":" + httpServletRequest.getServerPort() )
171                + httpServletRequest.getContextPath();
172        }
173    
174        protected <T> Map<String, T> getBeansOfType( ApplicationContext applicationContext, Class<T> clazz )
175        {
176            //TODO do some caching here !!!
177            // olamy : with plexus we get only roleHint
178            // as per convention we named spring bean role#hint remove role# if exists
179            Map<String, T> springBeans = applicationContext.getBeansOfType( clazz );
180    
181            Map<String, T> beans = new HashMap<String, T>( springBeans.size() );
182    
183            for ( Map.Entry<String, T> entry : springBeans.entrySet() )
184            {
185                String key = StringUtils.contains( entry.getKey(), '#' )
186                    ? StringUtils.substringAfterLast( entry.getKey(), "#" )
187                    : entry.getKey();
188                beans.put( key, entry.getValue() );
189            }
190            return beans;
191        }
192    
193        protected void triggerAuditEvent( String repositoryId, String filePath, String action )
194        {
195            AuditEvent auditEvent = new AuditEvent( repositoryId, getPrincipal(), filePath, action );
196            AuditInformation auditInformation = getAuditInformation();
197            auditEvent.setUserId( auditInformation.getUser() == null ? "" : auditInformation.getUser().getUsername() );
198            auditEvent.setRemoteIP( auditInformation.getRemoteAddr() );
199            for ( AuditListener auditListener : getAuditListeners() )
200            {
201                auditListener.auditEvent( auditEvent );
202            }
203        }
204    
205        /**
206         * @param artifact
207         * @return
208         */
209        protected String getArtifactUrl( Artifact artifact )
210            throws ArchivaRestServiceException
211        {
212            try
213            {
214    
215                if ( httpServletRequest == null )
216                {
217                    return null;
218                }
219    
220                StringBuilder sb = new StringBuilder( getBaseUrl() );
221    
222                sb.append( "/repository" );
223    
224                // FIXME when artifact come from a remote repository when have here the remote repo id
225                // we must replace it with a valid managed one available for the user.
226    
227                sb.append( '/' ).append( artifact.getContext() );
228    
229                sb.append( '/' ).append( StringUtils.replaceChars( artifact.getGroupId(), '.', '/' ) );
230                sb.append( '/' ).append( artifact.getArtifactId() );
231                if ( VersionUtil.isSnapshot( artifact.getVersion() ) )
232                {
233                    sb.append( '/' ).append( VersionUtil.getBaseVersion( artifact.getVersion() ) );
234                }
235                else
236                {
237                    sb.append( '/' ).append( artifact.getVersion() );
238                }
239                sb.append( '/' ).append( artifact.getArtifactId() );
240                sb.append( '-' ).append( artifact.getVersion() );
241                if ( StringUtils.isNotBlank( artifact.getClassifier() ) )
242                {
243                    sb.append( '-' ).append( artifact.getClassifier() );
244                }
245                // maven-plugin packaging is a jar
246                if ( StringUtils.equals( "maven-plugin", artifact.getPackaging() ) )
247                {
248                    sb.append( "jar" );
249                }
250                else
251                {
252                    sb.append( '.' ).append( artifact.getFileExtension() );
253                }
254    
255                return sb.toString();
256            }
257            catch ( RepositoryAdminException e )
258            {
259                throw new ArchivaRestServiceException( e.getMessage(),
260                                                       Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
261            }
262        }
263    
264        protected List<Artifact> buildArtifacts( List<ArtifactMetadata> artifactMetadatas, String repositoryId )
265            throws ArchivaRestServiceException
266        {
267            try
268            {
269                if ( artifactMetadatas != null && !artifactMetadatas.isEmpty() )
270                {
271                    List<Artifact> artifacts = new ArrayList<Artifact>( artifactMetadatas.size() );
272                    for ( ArtifactMetadata artifact : artifactMetadatas )
273                    {
274    
275                        ArtifactBuilder builder =
276                            new ArtifactBuilder().forArtifactMetadata( artifact ).withManagedRepositoryContent(
277                                repositoryContentFactory.getManagedRepositoryContent( repositoryId ) );
278                        Artifact art = builder.build();
279                        art.setUrl( getArtifactUrl( art ) );
280                        artifacts.add( art );
281                    }
282                    return artifacts;
283                }
284                return Collections.emptyList();
285            }
286            catch ( RepositoryException e )
287            {
288                log.error( e.getMessage(), e );
289                throw new ArchivaRestServiceException( e.getMessage(),
290                                                       Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
291            }
292        }
293    
294        protected Boolean doScanRepository( String repositoryId, boolean fullScan )
295        {
296            if ( repositoryTaskScheduler.isProcessingRepositoryTask( repositoryId ) )
297            {
298                log.info( "scanning of repository with id {} already scheduled", repositoryId );
299                return Boolean.FALSE;
300            }
301            RepositoryTask task = new RepositoryTask();
302            task.setRepositoryId( repositoryId );
303            task.setScanAll( fullScan );
304            try
305            {
306                repositoryTaskScheduler.queueTask( task );
307            }
308            catch ( TaskQueueException e )
309            {
310                log.error( "failed to schedule scanning of repo with id {}", repositoryId, e );
311                return false;
312            }
313            return true;
314        }
315    }