001package org.apache.archiva.audit; 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 org.apache.archiva.metadata.model.facets.AuditEvent; 023import org.apache.archiva.metadata.repository.MetadataRepository; 024import org.apache.archiva.metadata.repository.MetadataRepositoryException; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027import org.springframework.stereotype.Service; 028 029import java.text.ParseException; 030import java.text.SimpleDateFormat; 031import java.util.ArrayList; 032import java.util.Collection; 033import java.util.Collections; 034import java.util.Comparator; 035import java.util.Date; 036import java.util.List; 037import java.util.TimeZone; 038 039/** 040 * 041 */ 042@Service("auditManager#default") 043public class DefaultAuditManager 044 implements AuditManager 045{ 046 private static final int NUM_RECENT_EVENTS = 10; 047 048 private static final Logger log = LoggerFactory.getLogger( DefaultAuditManager.class ); 049 050 private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" ); 051 052 @Override 053 public List<AuditEvent> getMostRecentAuditEvents( MetadataRepository metadataRepository, 054 List<String> repositoryIds ) 055 throws MetadataRepositoryException 056 { 057 // TODO: consider a more efficient implementation that directly gets the last ten from the content repository 058 List<AuditRecord> records = new ArrayList<>(); 059 for ( String repositoryId : repositoryIds ) 060 { 061 List<String> names = metadataRepository.getMetadataFacets( repositoryId, AuditEvent.FACET_ID ); 062 for ( String name : names ) 063 { 064 records.add( new AuditRecord( repositoryId, name ) ); 065 } 066 } 067 Collections.sort( records ); 068 records = records.subList( 0, records.size() < NUM_RECENT_EVENTS ? records.size() : NUM_RECENT_EVENTS ); 069 070 List<AuditEvent> events = new ArrayList<>( records.size() ); 071 for ( AuditRecord record : records ) 072 { 073 AuditEvent auditEvent = (AuditEvent) metadataRepository.getMetadataFacet( record.repositoryId, 074 AuditEvent.FACET_ID, 075 record.name ); 076 events.add( auditEvent ); 077 } 078 return events; 079 } 080 081 @Override 082 public void addAuditEvent( MetadataRepository repository, AuditEvent event ) 083 throws MetadataRepositoryException 084 { 085 // ignore those with no repository - they will still be logged to the textual audit log 086 if ( event.getRepositoryId() != null ) 087 { 088 repository.addMetadataFacet( event.getRepositoryId(), event ); 089 } 090 } 091 092 @Override 093 public void deleteAuditEvents( MetadataRepository metadataRepository, String repositoryId ) 094 throws MetadataRepositoryException 095 { 096 metadataRepository.removeMetadataFacets( repositoryId, AuditEvent.FACET_ID ); 097 } 098 099 @Override 100 public List<AuditEvent> getAuditEventsInRange( MetadataRepository metadataRepository, 101 Collection<String> repositoryIds, Date startTime, Date endTime ) 102 throws MetadataRepositoryException 103 { 104 return getAuditEventsInRange( metadataRepository, repositoryIds, null, startTime, endTime ); 105 } 106 107 @Override 108 public List<AuditEvent> getAuditEventsInRange( MetadataRepository metadataRepository, 109 Collection<String> repositoryIds, String resource, Date startTime, 110 Date endTime ) 111 throws MetadataRepositoryException 112 { 113 List<AuditEvent> results = new ArrayList<>(); 114 for ( String repositoryId : repositoryIds ) 115 { 116 List<String> list = metadataRepository.getMetadataFacets( repositoryId, AuditEvent.FACET_ID ); 117 for ( String name : list ) 118 { 119 try 120 { 121 Date date = createNameFormat().parse( name ); 122 if ( ( startTime == null || !date.before( startTime ) ) && ( endTime == null || !date.after( 123 endTime ) ) ) 124 { 125 AuditEvent event = (AuditEvent) metadataRepository.getMetadataFacet( repositoryId, 126 AuditEvent.FACET_ID, 127 name ); 128 129 if ( resource == null || event.getResource().startsWith( resource ) ) 130 { 131 results.add( event ); 132 } 133 } 134 } 135 catch ( ParseException e ) 136 { 137 log.error( "Invalid audit event found in the metadata repository: " + e.getMessage() ); 138 // continue and ignore this one 139 } 140 } 141 } 142 Collections.sort( results, new Comparator<AuditEvent>() 143 { 144 @Override 145 public int compare( AuditEvent o1, AuditEvent o2 ) 146 { 147 return o2.getTimestamp().compareTo( o1.getTimestamp() ); 148 } 149 } ); 150 return results; 151 } 152 153 private static SimpleDateFormat createNameFormat() 154 { 155 SimpleDateFormat fmt = new SimpleDateFormat( AuditEvent.TIMESTAMP_FORMAT ); 156 fmt.setTimeZone( UTC_TIME_ZONE ); 157 return fmt; 158 } 159 160 private static final class AuditRecord 161 implements Comparable<AuditRecord> 162 { 163 private String repositoryId; 164 165 private String name; 166 167 public AuditRecord( String repositoryId, String name ) 168 { 169 this.repositoryId = repositoryId; 170 this.name = name; 171 } 172 173 @Override 174 public int compareTo( AuditRecord other ) 175 { 176 // reverse ordering 177 return other.name.compareTo( name ); 178 } 179 } 180}