blob: f9808ced8c9e39d8fd11ef1941168ddfa5d9c8d0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.ftpserver.impl;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.ftpserver.ftplet.FtpFile;
import org.apache.ftpserver.ftplet.User;
/**
* <strong>Internal class, do not use directly.</strong>
*
* This is FTP statistics implementation.
*
* TODO revisit concurrency, right now we're a bit over zealous with both Atomic*
* counters and synchronization
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
public class DefaultFtpStatistics implements ServerFtpStatistics {
private StatisticsObserver observer = null;
private FileObserver fileObserver = null;
private Date startTime = new Date();
private AtomicInteger uploadCount = new AtomicInteger(0);
private AtomicInteger downloadCount = new AtomicInteger(0);
private AtomicInteger deleteCount = new AtomicInteger(0);
private AtomicInteger mkdirCount = new AtomicInteger(0);
private AtomicInteger rmdirCount = new AtomicInteger(0);
private AtomicInteger currLogins = new AtomicInteger(0);
private AtomicInteger totalLogins = new AtomicInteger(0);
private AtomicInteger totalFailedLogins = new AtomicInteger(0);
private AtomicInteger currAnonLogins = new AtomicInteger(0);
private AtomicInteger totalAnonLogins = new AtomicInteger(0);
private AtomicInteger currConnections = new AtomicInteger(0);
private AtomicInteger totalConnections = new AtomicInteger(0);
private AtomicLong bytesUpload = new AtomicLong(0L);
private AtomicLong bytesDownload = new AtomicLong(0L);
private static class UserLogins {
private Map<InetAddress, AtomicInteger> perAddress = new ConcurrentHashMap<>();
public UserLogins(InetAddress address) {
// init with the first connection
totalLogins = new AtomicInteger(1);
perAddress.put(address, new AtomicInteger(1));
}
public AtomicInteger loginsFromInetAddress(InetAddress address) {
AtomicInteger logins = perAddress.get(address);
if (logins == null) {
logins = new AtomicInteger(0);
perAddress.put(address, logins);
}
return logins;
}
public AtomicInteger totalLogins;
}
/**
*The user login information.
*/
private Map<String, UserLogins> userLoginTable = new ConcurrentHashMap<>();
public static final String LOGIN_NUMBER = "login_number";
/**
* Set the observer.
*/
public void setObserver(final StatisticsObserver observer) {
this.observer = observer;
}
/**
* Set the file observer.
*/
public void setFileObserver(final FileObserver observer) {
fileObserver = observer;
}
// //////////////////////////////////////////////////////
// /////////////// All getter methods /////////////////
/**
* Get server start time.
*/
public Date getStartTime() {
if (startTime != null) {
return (Date) startTime.clone();
} else {
return null;
}
}
/**
* Get number of files uploaded.
*/
public int getTotalUploadNumber() {
return uploadCount.get();
}
/**
* Get number of files downloaded.
*/
public int getTotalDownloadNumber() {
return downloadCount.get();
}
/**
* Get number of files deleted.
*/
public int getTotalDeleteNumber() {
return deleteCount.get();
}
/**
* Get total number of bytes uploaded.
*/
public long getTotalUploadSize() {
return bytesUpload.get();
}
/**
* Get total number of bytes downloaded.
*/
public long getTotalDownloadSize() {
return bytesDownload.get();
}
/**
* Get total directory created.
*/
public int getTotalDirectoryCreated() {
return mkdirCount.get();
}
/**
* Get total directory removed.
*/
public int getTotalDirectoryRemoved() {
return rmdirCount.get();
}
/**
* Get total number of connections.
*/
public int getTotalConnectionNumber() {
return totalConnections.get();
}
/**
* Get current number of connections.
*/
public int getCurrentConnectionNumber() {
return currConnections.get();
}
/**
* Get total number of logins.
*/
public int getTotalLoginNumber() {
return totalLogins.get();
}
/**
* Get total failed login number.
*/
public int getTotalFailedLoginNumber() {
return totalFailedLogins.get();
}
/**
* Get current number of logins.
*/
public int getCurrentLoginNumber() {
return currLogins.get();
}
/**
* Get total number of anonymous logins.
*/
public int getTotalAnonymousLoginNumber() {
return totalAnonLogins.get();
}
/**
* Get current number of anonymous logins.
*/
public int getCurrentAnonymousLoginNumber() {
return currAnonLogins.get();
}
/**
* Get the login number for the specific user
*/
public synchronized int getCurrentUserLoginNumber(final User user) {
UserLogins userLogins = userLoginTable.get(user.getName());
if (userLogins == null) {// not found the login user's statistics info
return 0;
} else {
return userLogins.totalLogins.get();
}
}
/**
* Get the login number for the specific user from the ipAddress
*
* @param user
* login user account
* @param ipAddress
* the ip address of the remote user
*/
public synchronized int getCurrentUserLoginNumber(final User user,
final InetAddress ipAddress) {
UserLogins userLogins = userLoginTable.get(user.getName());
if (userLogins == null) {// not found the login user's statistics info
return 0;
} else {
return userLogins.loginsFromInetAddress(ipAddress).get();
}
}
// //////////////////////////////////////////////////////
// /////////////// All setter methods /////////////////
/**
* Increment upload count.
*/
public synchronized void setUpload(final FtpIoSession session,
final FtpFile file, final long size) {
uploadCount.incrementAndGet();
bytesUpload.addAndGet(size);
notifyUpload(session, file, size);
}
/**
* Increment download count.
*/
public synchronized void setDownload(final FtpIoSession session,
final FtpFile file, final long size) {
downloadCount.incrementAndGet();
bytesDownload.addAndGet(size);
notifyDownload(session, file, size);
}
/**
* Increment delete count.
*/
public synchronized void setDelete(final FtpIoSession session,
final FtpFile file) {
deleteCount.incrementAndGet();
notifyDelete(session, file);
}
/**
* Increment make directory count.
*/
public synchronized void setMkdir(final FtpIoSession session,
final FtpFile file) {
mkdirCount.incrementAndGet();
notifyMkdir(session, file);
}
/**
* Increment remove directory count.
*/
public synchronized void setRmdir(final FtpIoSession session,
final FtpFile file) {
rmdirCount.incrementAndGet();
notifyRmdir(session, file);
}
/**
* Increment open connection count.
*/
public synchronized void setOpenConnection(final FtpIoSession session) {
currConnections.incrementAndGet();
totalConnections.incrementAndGet();
notifyOpenConnection(session);
}
/**
* Decrement open connection count.
*/
public synchronized void setCloseConnection(final FtpIoSession session) {
if (currConnections.get() > 0) {
currConnections.decrementAndGet();
}
notifyCloseConnection(session);
}
/**
* New login.
*/
public synchronized void setLogin(final FtpIoSession session) {
currLogins.incrementAndGet();
totalLogins.incrementAndGet();
User user = session.getUser();
if ("anonymous".equals(user.getName())) {
currAnonLogins.incrementAndGet();
totalAnonLogins.incrementAndGet();
}
synchronized (user) {// thread safety is needed. Since the login occurrs
// at low frequency, this overhead is endurable
UserLogins statisticsTable = userLoginTable.get(user.getName());
if (statisticsTable == null) {
// the hash table that records the login information of the user
// and its ip address.
InetAddress address = null;
if (session.getRemoteAddress() instanceof InetSocketAddress) {
address = ((InetSocketAddress) session.getRemoteAddress())
.getAddress();
}
statisticsTable = new UserLogins(address);
userLoginTable.put(user.getName(), statisticsTable);
} else {
statisticsTable.totalLogins.incrementAndGet();
if (session.getRemoteAddress() instanceof InetSocketAddress) {
InetAddress address = ((InetSocketAddress) session
.getRemoteAddress()).getAddress();
statisticsTable.loginsFromInetAddress(address)
.incrementAndGet();
}
}
}
notifyLogin(session);
}
/**
* Increment failed login count.
*/
public synchronized void setLoginFail(final FtpIoSession session) {
totalFailedLogins.incrementAndGet();
notifyLoginFail(session);
}
/**
* User logout
*/
public synchronized void setLogout(final FtpIoSession session) {
User user = session.getUser();
if (user == null) {
return;
}
currLogins.decrementAndGet();
if ("anonymous".equals(user.getName())) {
currAnonLogins.decrementAndGet();
}
synchronized (user) {
UserLogins userLogins = userLoginTable.get(user.getName());
if (userLogins != null) {
userLogins.totalLogins.decrementAndGet();
if (session.getRemoteAddress() instanceof InetSocketAddress) {
InetAddress address = ((InetSocketAddress) session
.getRemoteAddress()).getAddress();
userLogins.loginsFromInetAddress(address).decrementAndGet();
}
}
}
notifyLogout(session);
}
// //////////////////////////////////////////////////////////
// /////////////// all observer methods ////////////////////
/**
* Observer upload notification.
*/
private void notifyUpload(final FtpIoSession session,
final FtpFile file, long size) {
StatisticsObserver observer = this.observer;
if (observer != null) {
observer.notifyUpload();
}
FileObserver fileObserver = this.fileObserver;
if (fileObserver != null) {
fileObserver.notifyUpload(session, file, size);
}
}
/**
* Observer download notification.
*/
private void notifyDownload(final FtpIoSession session,
final FtpFile file, final long size) {
StatisticsObserver observer = this.observer;
if (observer != null) {
observer.notifyDownload();
}
FileObserver fileObserver = this.fileObserver;
if (fileObserver != null) {
fileObserver.notifyDownload(session, file, size);
}
}
/**
* Observer delete notification.
*/
private void notifyDelete(final FtpIoSession session, final FtpFile file) {
StatisticsObserver observer = this.observer;
if (observer != null) {
observer.notifyDelete();
}
FileObserver fileObserver = this.fileObserver;
if (fileObserver != null) {
fileObserver.notifyDelete(session, file);
}
}
/**
* Observer make directory notification.
*/
private void notifyMkdir(final FtpIoSession session, final FtpFile file) {
StatisticsObserver observer = this.observer;
if (observer != null) {
observer.notifyMkdir();
}
FileObserver fileObserver = this.fileObserver;
if (fileObserver != null) {
fileObserver.notifyMkdir(session, file);
}
}
/**
* Observer remove directory notification.
*/
private void notifyRmdir(final FtpIoSession session, final FtpFile file) {
StatisticsObserver observer = this.observer;
if (observer != null) {
observer.notifyRmdir();
}
FileObserver fileObserver = this.fileObserver;
if (fileObserver != null) {
fileObserver.notifyRmdir(session, file);
}
}
/**
* Observer open connection notification.
*/
private void notifyOpenConnection(final FtpIoSession session) {
StatisticsObserver observer = this.observer;
if (observer != null) {
observer.notifyOpenConnection();
}
}
/**
* Observer close connection notification.
*/
private void notifyCloseConnection(final FtpIoSession session) {
StatisticsObserver observer = this.observer;
if (observer != null) {
observer.notifyCloseConnection();
}
}
/**
* Observer login notification.
*/
private void notifyLogin(final FtpIoSession session) {
StatisticsObserver observer = this.observer;
if (observer != null) {
// is anonymous login
User user = session.getUser();
boolean anonymous = false;
if (user != null) {
String login = user.getName();
anonymous = (login != null) && login.equals("anonymous");
}
observer.notifyLogin(anonymous);
}
}
/**
* Observer failed login notification.
*/
private void notifyLoginFail(final FtpIoSession session) {
StatisticsObserver observer = this.observer;
if (observer != null) {
if (session.getRemoteAddress() instanceof InetSocketAddress) {
observer.notifyLoginFail(((InetSocketAddress) session
.getRemoteAddress()).getAddress());
}
}
}
/**
* Observer logout notification.
*/
private void notifyLogout(final FtpIoSession session) {
StatisticsObserver observer = this.observer;
if (observer != null) {
// is anonymous login
User user = session.getUser();
boolean anonymous = false;
if (user != null) {
String login = user.getName();
anonymous = (login != null) && login.equals("anonymous");
}
observer.notifyLogout(anonymous);
}
}
/**
* Reset the cumulative counters.
*/
public synchronized void resetStatisticsCounters() {
startTime = new Date();
uploadCount.set(0);
downloadCount.set(0);
deleteCount.set(0);
mkdirCount.set(0);
rmdirCount.set(0);
totalLogins.set(0);
totalFailedLogins.set(0);
totalAnonLogins.set(0);
totalConnections.set(0);
bytesUpload.set(0);
bytesDownload.set(0);
}
}