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