blob: 16fe1417627640079f3d86c2c2aa8ac3b9d6234f [file] [log] [blame]
/*
* Copyright (c) 2004-2018 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.spi.server;
import org.eclipse.emf.cdo.internal.server.bundle.OM;
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.server.IRepository.WriteAccessHandler;
import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
import org.eclipse.emf.cdo.server.ITransaction;
import org.eclipse.emf.cdo.server.IView;
import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.container.ContainerEventAdapter;
import org.eclipse.net4j.util.container.IContainer;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.factory.ProductCreationException;
import org.eclipse.net4j.util.lifecycle.LifecycleHook;
import org.eclipse.net4j.util.om.log.Log;
import org.eclipse.net4j.util.om.log.RollingLog;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Eike Stepper
* @since 4.7
*/
public abstract class RepositoryActivityLog extends LifecycleHook<IRepository> implements Log
{
private final IListener sessionManagerListener = new ContainerEventAdapter<ISession>()
{
@Override
protected void onAdded(IContainer<ISession> container, ISession session)
{
sessionOpened(session, concurrentSessions.incrementAndGet(), sessions.incrementAndGet());
session.addListener(sessionListener);
}
@Override
protected void onRemoved(IContainer<ISession> container, ISession session)
{
session.removeListener(sessionListener);
sessionClosed(session, concurrentSessions.decrementAndGet());
}
};
private final IListener sessionListener = new ContainerEventAdapter<IView>()
{
@Override
protected void onAdded(IContainer<IView> container, IView view)
{
if (view instanceof ITransaction)
{
transactionOpened((ITransaction)view, concurrentTransactions.incrementAndGet(), transactions.incrementAndGet());
}
else
{
viewOpened(view, concurrentViews.incrementAndGet(), views.incrementAndGet());
}
}
@Override
protected void onRemoved(IContainer<IView> container, IView view)
{
if (view instanceof ITransaction)
{
transactionClosed((ITransaction)view, concurrentTransactions.decrementAndGet());
}
else
{
viewClosed(view, concurrentViews.decrementAndGet());
}
}
};
private final WriteAccessHandler writeAccessHandler = new WriteAccessHandler()
{
public void handleTransactionBeforeCommitting(ITransaction transaction, CommitContext commitContext, OMMonitor monitor) throws RuntimeException
{
commitStarted(commitContext, concurrentCommits.incrementAndGet(), commits.incrementAndGet());
}
public void handleTransactionAfterCommitted(ITransaction transaction, CommitContext commitContext, OMMonitor monitor)
{
commitFinished(commitContext, concurrentCommits.decrementAndGet());
}
};
private final AtomicInteger sessions = new AtomicInteger();
private final AtomicInteger views = new AtomicInteger();
private final AtomicInteger transactions = new AtomicInteger();
private final AtomicInteger commits = new AtomicInteger();
private final AtomicInteger concurrentSessions = new AtomicInteger();
private final AtomicInteger concurrentViews = new AtomicInteger();
private final AtomicInteger concurrentTransactions = new AtomicInteger();
private final AtomicInteger concurrentCommits = new AtomicInteger();
public RepositoryActivityLog()
{
}
public IRepository getRepository()
{
return getDelegate();
}
public void setRepository(IRepository repository)
{
setDelegate(repository);
}
protected void sessionOpened(ISession session, int concurrentSessions, int sessions)
{
log(formatSession(session) + " opened" + formatUser(session) + " (" + concurrentSessions + "/" + sessions + ")");
}
protected void sessionClosed(ISession session, int concurrentSessions)
{
log(formatSession(session) + " closed" + formatUser(session) + " (" + concurrentSessions + ")");
}
protected void viewOpened(IView view, int concurrentViews, int views)
{
log(formatView(view) + " opened" + formatUser(view.getSession()) + " (" + concurrentViews + "/" + views + ")");
}
protected void viewClosed(IView view, int concurrentViews)
{
log(formatView(view) + " closed" + formatUser(view.getSession()) + " (" + concurrentViews + ")");
}
protected void transactionOpened(ITransaction transaction, int concurrentTransactions, int transactions)
{
log(formatView(transaction) + " opened" + formatUser(transaction.getSession()) + " (" + concurrentTransactions + "/" + transactions + ")");
}
protected void transactionClosed(ITransaction transaction, int concurrentTransactions)
{
log(formatView(transaction) + " closed" + formatUser(transaction.getSession()) + " (" + concurrentTransactions + ")");
}
protected void commitStarted(CommitContext commitContext, int concurrentCommits, int commits)
{
ITransaction transaction = commitContext.getTransaction();
log(formatView(transaction) + " committing " + commitContext.getBranchPoint().getTimeStamp() + formatUser(transaction.getSession()) + " ("
+ concurrentCommits + "/" + commits + ")");
}
protected void commitFinished(CommitContext commitContext, int concurrentCommits)
{
ITransaction transaction = commitContext.getTransaction();
log(formatView(transaction) + (commitContext.getRollbackMessage() != null ? " committed " : " rolled back ") + commitContext.getBranchPoint().getTimeStamp()
+ formatUser(transaction.getSession()) + " (" + concurrentCommits + ")");
}
protected String formatSession(ISession session)
{
return "Session " + session.getSessionID();
}
protected String formatUser(ISession session)
{
String userID = session.getUserID();
return StringUtil.isEmpty(userID) ? "" : " by user " + userID;
}
protected String formatView(IView view)
{
return (view instanceof ITransaction ? "Transaction " : "View ") + view.getSessionID() + ":" + view.getViewID();
}
@Override
protected void hookDelegate(IRepository repository)
{
repository.getSessionManager().addListener(sessionManagerListener);
repository.addHandler(writeAccessHandler);
}
@Override
protected void unhookDelegate(IRepository repository)
{
repository.removeHandler(writeAccessHandler);
repository.getSessionManager().removeListener(sessionManagerListener);
}
/**
* @author Eike Stepper
* @since 4.7
*/
public static abstract class Factory extends org.eclipse.net4j.util.factory.PropertiesFactory
{
public static final String PRODUCT_GROUP = "org.eclipse.emf.cdo.server.repositoryActivityLogs"; //$NON-NLS-1$
public Factory(String type)
{
super(PRODUCT_GROUP, type);
}
@Override
protected abstract RepositoryActivityLog create(Map<String, String> properties) throws ProductCreationException;
}
/**
* @author Eike Stepper
* @since 4.7
*/
public static class Rolling extends RepositoryActivityLog
{
private final RollingLog rollingLog;
public Rolling(String logFile, long logSize)
{
rollingLog = new RollingLog(logFile, logSize);
}
public void log(String line)
{
rollingLog.log(line);
}
@Override
protected void delegateChanged(IRepository oldRepository, IRepository newRepository)
{
if (newRepository != null)
{
OM.LOG.info("Logging activities of repository " + newRepository.getName() + " to " + rollingLog.getLogFile());
}
}
@Override
protected void doActivate() throws Exception
{
rollingLog.activate();
super.doActivate();
}
@Override
protected void doDeactivate() throws Exception
{
super.doDeactivate();
rollingLog.deactivate();
}
/**
* @author Eike Stepper
*/
public static final class Factory extends RepositoryActivityLog.Factory
{
public static final String TYPE = "rolling"; //$NON-NLS-1$
public Factory()
{
super(TYPE);
}
@Override
protected RepositoryActivityLog create(Map<String, String> properties) throws ProductCreationException
{
String file = properties.get("file"); //$NON-NLS-1$
if (file == null)
{
file = "activities";
}
String size = properties.get("size"); //$NON-NLS-1$
if (StringUtil.isEmpty(size))
{
size = "100000000";
}
return new RepositoryActivityLog.Rolling(file, Long.parseLong(size));
}
}
}
}