mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-07 14:05:44 +01:00
implementation and use of repository dao
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||
* binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||
* nor the names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.repository.xml;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryDAO;
|
||||
import sonia.scm.store.StoreFactory;
|
||||
import sonia.scm.xml.AbstractXmlDAO;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
public class XmlRepositoryDAO
|
||||
extends AbstractXmlDAO<Repository, XmlRepositoryDatabase>
|
||||
implements RepositoryDAO
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final String STORE_NAME = "repositories";
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param storeFactory
|
||||
*/
|
||||
@Inject
|
||||
public XmlRepositoryDAO(StoreFactory storeFactory)
|
||||
{
|
||||
super(storeFactory.getStore(XmlRepositoryDatabase.class, STORE_NAME));
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @param name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(String type, String name)
|
||||
{
|
||||
return db.contains(type, name);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @param name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Repository get(String type, String name)
|
||||
{
|
||||
return db.get(type, name);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected Repository clone(Repository repository)
|
||||
{
|
||||
return repository.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected XmlRepositoryDatabase createNewDatabase()
|
||||
{
|
||||
return new XmlRepositoryDatabase();
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ package sonia.scm.repository.xml;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.xml.XmlDatabase;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
@@ -55,7 +56,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
*/
|
||||
@XmlRootElement(name = "repository-db")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class XmlRepositoryDatabase
|
||||
public class XmlRepositoryDatabase implements XmlDatabase<Repository>
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -105,6 +106,7 @@ public class XmlRepositoryDatabase
|
||||
*
|
||||
* @param repository
|
||||
*/
|
||||
@Override
|
||||
public void add(Repository repository)
|
||||
{
|
||||
repositoryMap.put(createKey(repository), repository);
|
||||
@@ -133,6 +135,7 @@ public class XmlRepositoryDatabase
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(String id)
|
||||
{
|
||||
return get(id) != null;
|
||||
@@ -166,8 +169,27 @@ public class XmlRepositoryDatabase
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Repository remove(String id)
|
||||
{
|
||||
Repository r = get(id);
|
||||
|
||||
remove(r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Collection<Repository> values()
|
||||
{
|
||||
return repositoryMap.values();
|
||||
@@ -197,6 +219,7 @@ public class XmlRepositoryDatabase
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Repository get(String id)
|
||||
{
|
||||
Repository repository = null;
|
||||
@@ -220,6 +243,7 @@ public class XmlRepositoryDatabase
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public long getCreationTime()
|
||||
{
|
||||
return creationTime;
|
||||
@@ -231,6 +255,7 @@ public class XmlRepositoryDatabase
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public long getLastModified()
|
||||
{
|
||||
return lastModified;
|
||||
@@ -244,6 +269,7 @@ public class XmlRepositoryDatabase
|
||||
*
|
||||
* @param creationTime
|
||||
*/
|
||||
@Override
|
||||
public void setCreationTime(long creationTime)
|
||||
{
|
||||
this.creationTime = creationTime;
|
||||
@@ -255,6 +281,7 @@ public class XmlRepositoryDatabase
|
||||
*
|
||||
* @param lastModified
|
||||
*/
|
||||
@Override
|
||||
public void setLastModified(long lastModified)
|
||||
{
|
||||
this.lastModified = lastModified;
|
||||
|
||||
@@ -55,6 +55,7 @@ import sonia.scm.repository.PermissionUtil;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryAllreadyExistExeption;
|
||||
import sonia.scm.repository.RepositoryBrowser;
|
||||
import sonia.scm.repository.RepositoryDAO;
|
||||
import sonia.scm.repository.RepositoryException;
|
||||
import sonia.scm.repository.RepositoryHandler;
|
||||
import sonia.scm.repository.RepositoryHandlerNotFoundException;
|
||||
@@ -64,8 +65,6 @@ import sonia.scm.repository.RepositoryHookTask;
|
||||
import sonia.scm.repository.RepositoryListener;
|
||||
import sonia.scm.repository.RepositoryNotFoundException;
|
||||
import sonia.scm.security.ScmSecurityException;
|
||||
import sonia.scm.store.Store;
|
||||
import sonia.scm.store.StoreFactory;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.CollectionAppender;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
@@ -99,9 +98,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final String STORE_NAME = "repositories";
|
||||
|
||||
/** Field description */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(XmlRepositoryManager.class);
|
||||
@@ -116,7 +112,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
*
|
||||
* @param contextProvider
|
||||
* @param securityContextProvider
|
||||
* @param storeFactory
|
||||
* @param repositoryDAO
|
||||
* @param handlerSet
|
||||
* @param repositoryListenersProvider
|
||||
* @param repositoryHooksProvider
|
||||
@@ -125,12 +121,12 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
public XmlRepositoryManager(
|
||||
SCMContextProvider contextProvider,
|
||||
Provider<WebSecurityContext> securityContextProvider,
|
||||
StoreFactory storeFactory, Set<RepositoryHandler> handlerSet,
|
||||
RepositoryDAO repositoryDAO, Set<RepositoryHandler> handlerSet,
|
||||
Provider<Set<RepositoryListener>> repositoryListenersProvider,
|
||||
Provider<Set<RepositoryHook>> repositoryHooksProvider)
|
||||
{
|
||||
this.securityContextProvider = securityContextProvider;
|
||||
this.store = storeFactory.getStore(XmlRepositoryDatabase.class, STORE_NAME);
|
||||
this.repositoryDAO = repositoryDAO;
|
||||
this.repositoryListenersProvider = repositoryListenersProvider;
|
||||
this.repositoryHooksProvider = repositoryHooksProvider;
|
||||
handlerMap = new HashMap<String, RepositoryHandler>();
|
||||
@@ -181,7 +177,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
SecurityUtil.assertIsAdmin(securityContextProvider);
|
||||
AssertUtil.assertIsValid(repository);
|
||||
|
||||
if (repositoryDB.contains(repository))
|
||||
if (repositoryDAO.contains(repository))
|
||||
{
|
||||
throw new RepositoryAllreadyExistExeption();
|
||||
}
|
||||
@@ -194,12 +190,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
getHandler(repository).create(repository);
|
||||
}
|
||||
|
||||
synchronized (XmlRepositoryDatabase.class)
|
||||
{
|
||||
repositoryDB.add(repository.clone());
|
||||
storeDB();
|
||||
}
|
||||
|
||||
repositoryDAO.add(repository);
|
||||
fireEvent(repository, HandlerEvent.CREATE);
|
||||
}
|
||||
|
||||
@@ -240,15 +231,10 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
|
||||
assertIsOwner(repository);
|
||||
|
||||
if (repositoryDB.contains(repository))
|
||||
if (repositoryDAO.contains(repository))
|
||||
{
|
||||
getHandler(repository).delete(repository);
|
||||
|
||||
synchronized (XmlRepositoryDatabase.class)
|
||||
{
|
||||
repositoryDB.remove(repository);
|
||||
storeDB();
|
||||
}
|
||||
repositoryDAO.delete(repository);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -273,7 +259,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
public void fireHookEvent(String type, String name, RepositoryHookEvent event)
|
||||
throws RepositoryNotFoundException
|
||||
{
|
||||
Repository repository = repositoryDB.get(type, name);
|
||||
Repository repository = repositoryDAO.get(type, name);
|
||||
|
||||
if (repository == null)
|
||||
{
|
||||
@@ -296,7 +282,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
public void fireHookEvent(String id, RepositoryHookEvent event)
|
||||
throws RepositoryNotFoundException
|
||||
{
|
||||
Repository repository = repositoryDB.get(id);
|
||||
Repository repository = repositoryDAO.get(id);
|
||||
|
||||
if (repository == null)
|
||||
{
|
||||
@@ -331,13 +317,6 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
@Override
|
||||
public void init(SCMContextProvider context)
|
||||
{
|
||||
repositoryDB = store.get();
|
||||
|
||||
if (repositoryDB == null)
|
||||
{
|
||||
repositoryDB = new XmlRepositoryDatabase();
|
||||
}
|
||||
|
||||
Set<RepositoryListener> listeners = repositoryListenersProvider.get();
|
||||
|
||||
if (Util.isNotEmpty(listeners))
|
||||
@@ -374,7 +353,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
|
||||
AssertUtil.assertIsValid(repository);
|
||||
|
||||
Repository notModifiedRepository = repositoryDB.get(repository.getType(),
|
||||
Repository notModifiedRepository = repositoryDAO.get(repository.getType(),
|
||||
repository.getName());
|
||||
|
||||
if (notModifiedRepository != null)
|
||||
@@ -382,13 +361,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
assertIsOwner(notModifiedRepository);
|
||||
getHandler(repository).modify(repository);
|
||||
repository.setLastModified(System.currentTimeMillis());
|
||||
|
||||
synchronized (XmlRepositoryDatabase.class)
|
||||
{
|
||||
repositoryDB.remove(repository);
|
||||
repositoryDB.add(repository.clone());
|
||||
storeDB();
|
||||
}
|
||||
repositoryDAO.modify(repository);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -415,7 +388,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
AssertUtil.assertIsNotNull(repository);
|
||||
assertIsReader(repository);
|
||||
|
||||
Repository fresh = repositoryDB.get(repository.getType(),
|
||||
Repository fresh = repositoryDAO.get(repository.getType(),
|
||||
repository.getName());
|
||||
|
||||
if (fresh != null)
|
||||
@@ -444,7 +417,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
{
|
||||
AssertUtil.assertIsNotEmpty(id);
|
||||
|
||||
Repository repository = repositoryDB.get(id);
|
||||
Repository repository = repositoryDAO.get(id);
|
||||
|
||||
if (repository != null)
|
||||
{
|
||||
@@ -470,7 +443,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
AssertUtil.assertIsNotEmpty(type);
|
||||
AssertUtil.assertIsNotEmpty(name);
|
||||
|
||||
Repository repository = repositoryDB.get(type, name);
|
||||
Repository repository = repositoryDAO.get(type, name);
|
||||
|
||||
if (repository != null)
|
||||
{
|
||||
@@ -500,7 +473,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
{
|
||||
List<Repository> repositories = new ArrayList<Repository>();
|
||||
|
||||
for (Repository repository : repositoryDB.values())
|
||||
for (Repository repository : repositoryDAO.getAll())
|
||||
{
|
||||
if (handlerMap.containsKey(repository.getType()) && isReader(repository))
|
||||
{
|
||||
@@ -545,7 +518,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
public Collection<Repository> getAll(Comparator<Repository> comparator,
|
||||
int start, int limit)
|
||||
{
|
||||
return Util.createSubCollection(repositoryDB.values(), comparator,
|
||||
return Util.createSubCollection(repositoryDAO.getAll(), comparator,
|
||||
new CollectionAppender<Repository>()
|
||||
{
|
||||
@Override
|
||||
@@ -703,7 +676,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
|
||||
if (handlerMap.containsKey(type))
|
||||
{
|
||||
Collection<Repository> repositories = repositoryDB.values();
|
||||
Collection<Repository> repositories = repositoryDAO.getAll();
|
||||
|
||||
for (Repository r : repositories)
|
||||
{
|
||||
@@ -781,7 +754,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
@Override
|
||||
public Long getLastModified()
|
||||
{
|
||||
return repositoryDB.getLastModified();
|
||||
return repositoryDAO.getLastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -905,16 +878,6 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
PermissionType.READ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
private void storeDB()
|
||||
{
|
||||
repositoryDB.setLastModified(System.currentTimeMillis());
|
||||
store.set(repositoryDB);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -987,14 +950,11 @@ public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private final Store<XmlRepositoryDatabase> store;
|
||||
|
||||
/** Field description */
|
||||
private Map<String, RepositoryHandler> handlerMap;
|
||||
|
||||
/** Field description */
|
||||
private XmlRepositoryDatabase repositoryDB;
|
||||
private RepositoryDAO repositoryDAO;
|
||||
|
||||
/** Field description */
|
||||
private Provider<Set<RepositoryHook>> repositoryHooksProvider;
|
||||
|
||||
@@ -273,7 +273,7 @@ public abstract class AbstractXmlDAO<I extends ModelObject,
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
private void storeDB()
|
||||
protected void storeDB()
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
@@ -290,5 +290,5 @@ public abstract class AbstractXmlDAO<I extends ModelObject,
|
||||
private final Store<T> store;
|
||||
|
||||
/** Field description */
|
||||
private T db;
|
||||
protected T db;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.google.inject.Provider;
|
||||
import org.junit.Test;
|
||||
|
||||
import sonia.scm.Type;
|
||||
import sonia.scm.repository.xml.XmlRepositoryDAO;
|
||||
import sonia.scm.repository.xml.XmlRepositoryManager;
|
||||
import sonia.scm.store.JAXBStoreFactory;
|
||||
import sonia.scm.store.StoreFactory;
|
||||
@@ -132,10 +133,12 @@ public class XmlRepositoryManagerTest extends RepositoryManagerTestBase
|
||||
|
||||
when(hookProvider.get()).thenReturn(new HashSet<RepositoryHook>());
|
||||
|
||||
XmlRepositoryDAO repositoryDAO = new XmlRepositoryDAO(factory);
|
||||
|
||||
return new XmlRepositoryManager(contextProvider,
|
||||
MockUtil.getAdminSecurityContextProvider(),
|
||||
factory, handlerSet, listenerProvider,
|
||||
hookProvider);
|
||||
repositoryDAO, handlerSet,
|
||||
listenerProvider, hookProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,7 +51,9 @@ import sonia.scm.filter.AdminSecurityFilter;
|
||||
import sonia.scm.filter.BaseUrlFilter;
|
||||
import sonia.scm.filter.GZipFilter;
|
||||
import sonia.scm.filter.SecurityFilter;
|
||||
import sonia.scm.group.GroupDAO;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.group.xml.XmlGroupDAO;
|
||||
import sonia.scm.group.xml.XmlGroupManager;
|
||||
import sonia.scm.io.DefaultFileSystem;
|
||||
import sonia.scm.io.FileSystem;
|
||||
@@ -65,8 +67,10 @@ import sonia.scm.repository.ChangesetViewerUtil;
|
||||
import sonia.scm.repository.DefaultRepositoryProvider;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryBrowserUtil;
|
||||
import sonia.scm.repository.RepositoryDAO;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryProvider;
|
||||
import sonia.scm.repository.xml.XmlRepositoryDAO;
|
||||
import sonia.scm.repository.xml.XmlRepositoryManager;
|
||||
import sonia.scm.resources.DefaultResourceManager;
|
||||
import sonia.scm.resources.DevelopmentResourceManager;
|
||||
@@ -88,7 +92,9 @@ import sonia.scm.url.RestXmlUrlProvider;
|
||||
import sonia.scm.url.UrlProvider;
|
||||
import sonia.scm.url.UrlProviderFactory;
|
||||
import sonia.scm.url.WebUIUrlProvider;
|
||||
import sonia.scm.user.UserDAO;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.user.xml.XmlUserDAO;
|
||||
import sonia.scm.user.xml.XmlUserManager;
|
||||
import sonia.scm.util.DebugServlet;
|
||||
import sonia.scm.util.ScmConfigurationUtil;
|
||||
@@ -118,10 +124,6 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import sonia.scm.group.GroupDAO;
|
||||
import sonia.scm.group.xml.XmlGroupDAO;
|
||||
import sonia.scm.user.UserDAO;
|
||||
import sonia.scm.user.xml.XmlUserDAO;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -258,6 +260,7 @@ public class ScmServletModule extends ServletModule
|
||||
// bind dao
|
||||
bind(GroupDAO.class, XmlGroupDAO.class);
|
||||
bind(UserDAO.class, XmlUserDAO.class);
|
||||
bind(RepositoryDAO.class, XmlRepositoryDAO.class);
|
||||
|
||||
// bind(RepositoryManager.class).annotatedWith(Undecorated.class).to(
|
||||
// BasicRepositoryManager.class);
|
||||
|
||||
Reference in New Issue
Block a user