From 3a1b1d9a1521beb5b9a89a9d2e093712ac73fe4d Mon Sep 17 00:00:00 2001 From: robin shine Date: Sun, 29 Sep 2013 20:56:18 +0800 Subject: [PATCH 1/3] Some minor fixes. --- .../com/pmease/gitop/core/model/User.java | 19 ------------------- .../gitop/core/permission/UserRealm.java | 2 +- .../gitop/web/resource/TestResource.java | 2 ++ 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java b/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java index a60441c00a..d63809f7c4 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java @@ -24,16 +24,6 @@ import com.pmease.gitop.core.permission.object.ProtectedObject; import com.pmease.gitop.core.permission.object.UserBelonging; import com.pmease.gitop.core.permission.operation.GeneralOperation; -/** - * This class represents either a project or an user in the system. - *

- * In Gitop, users and projects are the same thing. - * If necessary, you can always treat an user account as a project account. - * {@link Project} and {@link Team} are always created under a specific account. - * - * @author robin - * - */ @SuppressWarnings("serial") @Entity @Editable @@ -49,10 +39,8 @@ public class User extends AbstractUser implements ProtectedObject { @Column(nullable=false) private String email; - @Column private String displayName; - @Column private String avatarUrl; private boolean admin; @@ -217,13 +205,6 @@ public class User extends AbstractUser implements ProtectedObject { } } - public static User anonymous() { - User user = new User(); - user.setId(0L); - user.setName("Guest"); - return user; - } - @Override public boolean implies(Permission permission) { // Administrator can do anything diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/permission/UserRealm.java b/gitop.core/src/main/java/com/pmease/gitop/core/permission/UserRealm.java index 0b6b49c654..3ff2ac071f 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/permission/UserRealm.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/permission/UserRealm.java @@ -30,7 +30,7 @@ public class UserRealm extends AbstractRealm { if (userId != 0L) { return userManager.load(userId); } else { - return User.anonymous(); + return User.ANONYMOUS; } } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/resource/TestResource.java b/gitop.web/src/main/java/com/pmease/gitop/web/resource/TestResource.java index 3a3dbd3418..f2a27f52a0 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/resource/TestResource.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/resource/TestResource.java @@ -28,7 +28,9 @@ import com.pmease.gitop.web.SitePaths; @Path("/file") public class TestResource { + @SuppressWarnings("unused") private static final String SUCCESS_RESPONSE = "Successful"; + @SuppressWarnings("unused") private static final String FAILED_RESPONSE = "Failed"; @POST From aa695312628b3f9786608afbaacfc89e0f4aed17 Mon Sep 17 00:00:00 2001 From: robin shine Date: Mon, 30 Sep 2013 17:17:10 +0800 Subject: [PATCH 2/3] Remove servlet/filter auto-configure from commons projects. Instead add them into gitop projects for flexibility. Change to use GitFilter instead of GitServlet so that Git repository can be served without a prefix. --- commons.git/pom.xml | 5 -- commons.hibernate/pom.xml | 5 -- .../commons/hibernate/DefaultUnitOfWork.java | 5 ++ .../commons/hibernate/HibernateModule.java | 3 - .../HibernateServletContextConfigurator.java | 28 --------- .../pmease/commons/hibernate/UnitOfWork.java | 2 + commons.jersey/pom.xml | 7 +-- .../pmease/commons/jersey/DummyResource.java | 16 ------ .../pmease/commons/jersey/JerseyModule.java | 34 ----------- .../com/pmease/commons/jetty/JettyPlugin.java | 6 +- ...igurator.java => ServletConfigurator.java} | 2 +- commons.shiro/pom.xml | 7 +-- .../com/pmease/commons/shiro/ShiroModule.java | 26 +-------- .../pmease/commons/util/ObjectReference.java | 8 +++ commons.wicket/pom.xml | 5 -- .../pmease/commons/wicket/WicketModule.java | 3 - .../WicketServletContextConfigurator.java | 31 ---------- gitop.core/pom.xml | 7 ++- .../{GitopModule.java => CoreModule.java} | 6 +- .../gitop/core/CoreServletConfigurator.java | 53 +++++++++++++++++ .../core/{GitServlet.java => GitFilter.java} | 49 ++++++++++++---- .../core/GitServletContextConfigurator.java | 25 -------- gitop.product/pom.xml | 5 ++ ...igurator.java => ProductConfigurator.java} | 4 +- .../pmease/gitop/product/ProductModule.java | 7 ++- ...r.java => ProductServletConfigurator.java} | 11 ++-- gitop.rest/pom.xml | 57 +++++++++++++++++++ .../com/pmease/gitop/rest/RestModule.java | 29 ++++++++++ gitop.web/pom.xml | 10 ++-- .../java/com/pmease/gitop/web/WebModule.java | 26 +-------- .../gitop/web/WebServletConfigurator.java | 47 +++++++++++++++ .../com/pmease/gitop/web/WicketConfig.java | 29 ---------- 32 files changed, 277 insertions(+), 281 deletions(-) delete mode 100644 commons.hibernate/src/main/java/com/pmease/commons/hibernate/HibernateServletContextConfigurator.java delete mode 100644 commons.jersey/src/main/java/com/pmease/commons/jersey/DummyResource.java rename commons.jetty/src/main/java/com/pmease/commons/jetty/{ServletContextConfigurator.java => ServletConfigurator.java} (81%) delete mode 100644 commons.wicket/src/main/java/com/pmease/commons/wicket/WicketServletContextConfigurator.java rename gitop.core/src/main/java/com/pmease/gitop/core/{GitopModule.java => CoreModule.java} (87%) create mode 100644 gitop.core/src/main/java/com/pmease/gitop/core/CoreServletConfigurator.java rename gitop.core/src/main/java/com/pmease/gitop/core/{GitServlet.java => GitFilter.java} (77%) delete mode 100644 gitop.core/src/main/java/com/pmease/gitop/core/GitServletContextConfigurator.java rename gitop.product/src/main/java/com/pmease/gitop/product/{GitopServerConfigurator.java => ProductConfigurator.java} (89%) rename gitop.product/src/main/java/com/pmease/gitop/product/{GitopServletContextConfigurator.java => ProductServletConfigurator.java} (75%) create mode 100644 gitop.rest/pom.xml create mode 100644 gitop.rest/src/main/java/com/pmease/gitop/rest/RestModule.java create mode 100644 gitop.web/src/main/java/com/pmease/gitop/web/WebServletConfigurator.java delete mode 100644 gitop.web/src/main/java/com/pmease/gitop/web/WicketConfig.java diff --git a/commons.git/pom.xml b/commons.git/pom.xml index e7e9e80f61..7e0b38673e 100644 --- a/commons.git/pom.xml +++ b/commons.git/pom.xml @@ -43,11 +43,6 @@ commons.util 1.0.29 - - com.pmease - commons.jetty - 1.0.29 - diff --git a/commons.hibernate/pom.xml b/commons.hibernate/pom.xml index 8386d86b2a..fede29b885 100644 --- a/commons.hibernate/pom.xml +++ b/commons.hibernate/pom.xml @@ -76,11 +76,6 @@ jtds 1.3.0 - - com.pmease - commons.jetty - 1.0.29 - diff --git a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/DefaultUnitOfWork.java b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/DefaultUnitOfWork.java index d28d74390f..9db655b7e7 100644 --- a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/DefaultUnitOfWork.java +++ b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/DefaultUnitOfWork.java @@ -65,4 +65,9 @@ public class DefaultUnitOfWork implements UnitOfWork, Provider { return sessionFactoryProvider.get(); } + @Override + public void reset() { + sessionReferenceHolder.get().reset(); + } + } \ No newline at end of file diff --git a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/HibernateModule.java b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/HibernateModule.java index 781f8c26d8..636d1ba73c 100644 --- a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/HibernateModule.java +++ b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/HibernateModule.java @@ -13,7 +13,6 @@ import com.google.inject.name.Names; import com.google.inject.util.Providers; import com.pmease.commons.hibernate.dao.DefaultGeneralDao; import com.pmease.commons.hibernate.dao.GeneralDao; -import com.pmease.commons.jetty.ServletContextConfigurator; import com.pmease.commons.loader.AbstractPlugin; import com.pmease.commons.loader.AbstractPluginModule; @@ -51,8 +50,6 @@ public class HibernateModule extends AbstractPluginModule { Matchers.any(), Matchers.annotatedWith(Sessional.class), sessionInterceptor); - - contribute(ServletContextConfigurator.class, HibernateServletContextConfigurator.class); } @Override diff --git a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/HibernateServletContextConfigurator.java b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/HibernateServletContextConfigurator.java deleted file mode 100644 index 37dee11e1a..0000000000 --- a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/HibernateServletContextConfigurator.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.pmease.commons.hibernate; - -import java.util.EnumSet; - -import javax.inject.Inject; -import javax.servlet.DispatcherType; - -import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.servlet.ServletContextHandler; - -import com.pmease.commons.jetty.ServletContextConfigurator; - -public class HibernateServletContextConfigurator implements ServletContextConfigurator { - - private final HibernateFilter hibernateFilter; - - @Inject - public HibernateServletContextConfigurator(HibernateFilter hibernateFilter) { - this.hibernateFilter = hibernateFilter; - } - - @Override - public void configure(ServletContextHandler context) { - FilterHolder filterHolder = new FilterHolder(hibernateFilter); - context.addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); - } - -} diff --git a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/UnitOfWork.java b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/UnitOfWork.java index 259576cea6..647c8a60bc 100644 --- a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/UnitOfWork.java +++ b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/UnitOfWork.java @@ -25,6 +25,8 @@ public interface UnitOfWork { void end(); + void reset(); + Session getSession(); SessionFactory getSessionFactory(); diff --git a/commons.jersey/pom.xml b/commons.jersey/pom.xml index 8b3320743d..dd69b721de 100644 --- a/commons.jersey/pom.xml +++ b/commons.jersey/pom.xml @@ -42,12 +42,7 @@ com.sun.jersey.contribs jersey-guice ${jerseyVersion} - - - com.pmease - commons.shiro - 1.0.30 - + diff --git a/commons.jersey/src/main/java/com/pmease/commons/jersey/DummyResource.java b/commons.jersey/src/main/java/com/pmease/commons/jersey/DummyResource.java deleted file mode 100644 index 4b27c4ccbf..0000000000 --- a/commons.jersey/src/main/java/com/pmease/commons/jersey/DummyResource.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.pmease.commons.jersey; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; - -@Path("/dummy") -public class DummyResource { - - @GET - @Produces("text/plain") - public String get() { - return "Dummy's gold."; - } - -} diff --git a/commons.jersey/src/main/java/com/pmease/commons/jersey/JerseyModule.java b/commons.jersey/src/main/java/com/pmease/commons/jersey/JerseyModule.java index 58f9c1b807..0473233ef3 100644 --- a/commons.jersey/src/main/java/com/pmease/commons/jersey/JerseyModule.java +++ b/commons.jersey/src/main/java/com/pmease/commons/jersey/JerseyModule.java @@ -1,12 +1,6 @@ package com.pmease.commons.jersey; -import org.apache.shiro.web.filter.mgt.FilterChainManager; - import com.pmease.commons.loader.AbstractPluginModule; -import com.pmease.commons.shiro.FilterChainConfigurator; -import com.pmease.commons.util.EasyMap; -import com.sun.jersey.guice.JerseyServletModule; -import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; /** * NOTE: Do not forget to rename moduleClass property defined in the pom if @@ -15,38 +9,10 @@ import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; */ public class JerseyModule extends AbstractPluginModule { - public static final String REST_PATH = "rest"; - @Override protected void configure() { super.configure(); - install(new JerseyServletModule() { - - protected void configureServlets() { - // Bind at least one resource here as otherwise Jersey will report error. - bind(DummyResource.class); - - // Route all RESTful requests through GuiceContainer - serve(getRestPath()).with( - GuiceContainer.class, - EasyMap.of("com.sun.jersey.api.json.POJOMappingFeature", "true")); - } - - protected String getRestPath() { - return "/" + REST_PATH + "/*"; - } - - }); - - contribute(FilterChainConfigurator.class, new FilterChainConfigurator() { - - @Override - public void configure(FilterChainManager filterChainManager) { - filterChainManager.createChain("/" + REST_PATH + "/**", "noSessionCreation, authcBasic"); - } - - }); } } diff --git a/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyPlugin.java b/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyPlugin.java index 21cecd6ebf..41896b8cd4 100644 --- a/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyPlugin.java +++ b/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyPlugin.java @@ -31,12 +31,12 @@ public class JettyPlugin extends AbstractPlugin { private final Set serverConfigurators; - private final Set servletContextConfigurators; + private final Set servletContextConfigurators; @Inject public JettyPlugin( Set serverConfigurators, - Set servletContextConfigurators) { + Set servletContextConfigurators) { this.serverConfigurators = serverConfigurators; this.servletContextConfigurators = servletContextConfigurators; } @@ -76,7 +76,7 @@ public class JettyPlugin extends AbstractPlugin { context.addFilter(DisableTraceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); - for (ServletContextConfigurator configurator: servletContextConfigurators) + for (ServletConfigurator configurator: servletContextConfigurators) configurator.configure(context); /* diff --git a/commons.jetty/src/main/java/com/pmease/commons/jetty/ServletContextConfigurator.java b/commons.jetty/src/main/java/com/pmease/commons/jetty/ServletConfigurator.java similarity index 81% rename from commons.jetty/src/main/java/com/pmease/commons/jetty/ServletContextConfigurator.java rename to commons.jetty/src/main/java/com/pmease/commons/jetty/ServletConfigurator.java index 5e85ec8eef..cf3c009171 100644 --- a/commons.jetty/src/main/java/com/pmease/commons/jetty/ServletContextConfigurator.java +++ b/commons.jetty/src/main/java/com/pmease/commons/jetty/ServletConfigurator.java @@ -5,6 +5,6 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import com.pmease.commons.loader.ExtensionPoint; @ExtensionPoint -public interface ServletContextConfigurator { +public interface ServletConfigurator { void configure(ServletContextHandler context); } diff --git a/commons.shiro/pom.xml b/commons.shiro/pom.xml index ae18176b3a..bbf3ea87b3 100644 --- a/commons.shiro/pom.xml +++ b/commons.shiro/pom.xml @@ -37,12 +37,7 @@ org.apache.shiro shiro-web ${shiroVersion} - - - com.pmease - commons.jetty - 1.0.29 - + com.pmease commons.hibernate diff --git a/commons.shiro/src/main/java/com/pmease/commons/shiro/ShiroModule.java b/commons.shiro/src/main/java/com/pmease/commons/shiro/ShiroModule.java index 4d5f291edb..fa003df023 100644 --- a/commons.shiro/src/main/java/com/pmease/commons/shiro/ShiroModule.java +++ b/commons.shiro/src/main/java/com/pmease/commons/shiro/ShiroModule.java @@ -1,23 +1,15 @@ package com.pmease.commons.shiro; -import java.util.EnumSet; - import javax.inject.Singleton; -import javax.servlet.DispatcherType; import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.authc.credential.DefaultPasswordService; import org.apache.shiro.authc.credential.PasswordService; import org.apache.shiro.guice.aop.ShiroAopModule; -import org.apache.shiro.web.env.EnvironmentLoader; -import org.apache.shiro.web.env.EnvironmentLoaderListener; import org.apache.shiro.web.filter.mgt.FilterChainResolver; import org.apache.shiro.web.mgt.WebSecurityManager; import org.apache.shiro.web.servlet.ShiroFilter; -import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.servlet.ServletContextHandler; -import com.pmease.commons.jetty.ServletContextConfigurator; import com.pmease.commons.loader.AbstractPluginModule; /** @@ -36,23 +28,9 @@ public class ShiroModule extends AbstractPluginModule { bind(BasicAuthenticationFilter.class); bind(PasswordService.class).to(DefaultPasswordService.class).in(Singleton.class); bind(CredentialsMatcher.class).to(DefaultPasswordMatcher.class); - + bind(ShiroFilter.class); + install(new ShiroAopModule()); - - contribute(ServletContextConfigurator.class, new ServletContextConfigurator() { - - @Override - public void configure(ServletContextHandler context) { - context.setInitParameter( - EnvironmentLoader.ENVIRONMENT_CLASS_PARAM, - DefaultWebEnvironment.class.getName()); - - context.addEventListener(new EnvironmentLoaderListener()); - - context.addFilter(new FilterHolder(new ShiroFilter()), "/*", EnumSet.allOf(DispatcherType.class)); - } - - }); } } diff --git a/commons.util/src/main/java/com/pmease/commons/util/ObjectReference.java b/commons.util/src/main/java/com/pmease/commons/util/ObjectReference.java index 042f215f31..e746beef4f 100644 --- a/commons.util/src/main/java/com/pmease/commons/util/ObjectReference.java +++ b/commons.util/src/main/java/com/pmease/commons/util/ObjectReference.java @@ -35,6 +35,14 @@ public abstract class ObjectReference { object = null; } } + + public synchronized void reset() { + count = 0; + if (object != null) { + closeObject(object); + object = null; + } + } protected abstract void closeObject(T object); } diff --git a/commons.wicket/pom.xml b/commons.wicket/pom.xml index e0b6325a70..f5bd95aa2b 100644 --- a/commons.wicket/pom.xml +++ b/commons.wicket/pom.xml @@ -53,11 +53,6 @@ commons.loader 1.0.29 - - com.pmease - commons.jetty - 1.0.29 - com.pmease commons.editable diff --git a/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketModule.java b/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketModule.java index bcfe5e9997..27dbb5ff7d 100644 --- a/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketModule.java +++ b/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketModule.java @@ -4,7 +4,6 @@ import org.apache.wicket.protocol.http.WicketFilter; import org.apache.wicket.protocol.http.WicketServlet; import com.pmease.commons.editable.EditSupport; -import com.pmease.commons.jetty.ServletContextConfigurator; import com.pmease.commons.loader.AbstractPluginModule; import com.pmease.commons.wicket.editable.EditHelper; @@ -17,8 +16,6 @@ public class WicketModule extends AbstractPluginModule { bind(WicketServlet.class).to(DefaultWicketServlet.class); bind(WicketFilter.class).to(DefaultWicketFilter.class); - contribute(ServletContextConfigurator.class, WicketServletContextConfigurator.class); - contributeFromPackage(EditSupport.class, EditHelper.class); } diff --git a/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketServletContextConfigurator.java b/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketServletContextConfigurator.java deleted file mode 100644 index d73d1c8bb2..0000000000 --- a/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketServletContextConfigurator.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.pmease.commons.wicket; - -import javax.inject.Inject; - -import org.apache.wicket.protocol.http.WicketServlet; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; - -import com.pmease.commons.jetty.ServletContextConfigurator; - -public class WicketServletContextConfigurator implements ServletContextConfigurator { - - private final WicketServlet wicketServlet; - - @Inject - public WicketServletContextConfigurator(WicketServlet wicketServlet) { - this.wicketServlet = wicketServlet; - } - - @Override - public void configure(ServletContextHandler context) { - ServletHolder servletHolder = new ServletHolder(wicketServlet); - - /* - * Add wicket servlet as the default servlet which will serve all requests failed to - * match a path pattern - */ - context.addServlet(servletHolder, "/"); - } - -} diff --git a/gitop.core/pom.xml b/gitop.core/pom.xml index 0803d9a05a..57b35bf9d6 100644 --- a/gitop.core/pom.xml +++ b/gitop.core/pom.xml @@ -46,6 +46,11 @@ commons.editable 1.0.0 + + com.pmease + commons.jetty + 1.0.29 + @@ -65,7 +70,7 @@ - com.pmease.gitop.core.GitopModule + com.pmease.gitop.core.CoreModule 1.0.30 diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/GitopModule.java b/gitop.core/src/main/java/com/pmease/gitop/core/CoreModule.java similarity index 87% rename from gitop.core/src/main/java/com/pmease/gitop/core/GitopModule.java rename to gitop.core/src/main/java/com/pmease/gitop/core/CoreModule.java index 3a96a1bc86..0f36170e38 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/GitopModule.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/CoreModule.java @@ -8,7 +8,7 @@ import org.hibernate.cfg.NamingStrategy; import com.pmease.commons.hibernate.AbstractEntity; import com.pmease.commons.hibernate.ModelProvider; import com.pmease.commons.hibernate.PrefixedNamingStrategy; -import com.pmease.commons.jetty.ServletContextConfigurator; +import com.pmease.commons.jetty.ServletConfigurator; import com.pmease.commons.loader.AbstractPlugin; import com.pmease.commons.loader.AbstractPluginModule; import com.pmease.commons.shiro.AbstractRealm; @@ -20,7 +20,7 @@ import com.pmease.gitop.core.permission.UserRealm; * NOTE: Do not forget to rename moduleClass property defined in the pom if you've renamed this class. * */ -public class GitopModule extends AbstractPluginModule { +public class CoreModule extends AbstractPluginModule { @Override protected void configure() { @@ -42,7 +42,7 @@ public class GitopModule extends AbstractPluginModule { }); - contribute(ServletContextConfigurator.class, GitServletContextConfigurator.class); + contribute(ServletConfigurator.class, CoreServletConfigurator.class); } @Override diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/CoreServletConfigurator.java b/gitop.core/src/main/java/com/pmease/gitop/core/CoreServletConfigurator.java new file mode 100644 index 0000000000..97eac1d1c9 --- /dev/null +++ b/gitop.core/src/main/java/com/pmease/gitop/core/CoreServletConfigurator.java @@ -0,0 +1,53 @@ +package com.pmease.gitop.core; + +import java.util.EnumSet; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.servlet.DispatcherType; + +import org.apache.shiro.web.env.EnvironmentLoader; +import org.apache.shiro.web.env.EnvironmentLoaderListener; +import org.apache.shiro.web.servlet.ShiroFilter; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.ServletContextHandler; + +import com.pmease.commons.hibernate.HibernateFilter; +import com.pmease.commons.jetty.ServletConfigurator; +import com.pmease.commons.shiro.DefaultWebEnvironment; + +@Singleton +public class CoreServletConfigurator implements ServletConfigurator { + + private final ShiroFilter shiroFilter; + + private final GitFilter gitFilter; + + private final HibernateFilter hibernateFilter; + + @Inject + public CoreServletConfigurator(HibernateFilter hibernateFilter, ShiroFilter shiroFilter, GitFilter gitFilter) { + this.hibernateFilter = hibernateFilter; + this.shiroFilter = shiroFilter; + this.gitFilter = gitFilter; + } + + @Override + public void configure(ServletContextHandler context) { + FilterHolder filterHolder = new FilterHolder(hibernateFilter); + context.addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); + + context.setInitParameter( + EnvironmentLoader.ENVIRONMENT_CLASS_PARAM, + DefaultWebEnvironment.class.getName()); + + context.addEventListener(new EnvironmentLoaderListener()); + + filterHolder = new FilterHolder(shiroFilter); + context.addFilter(filterHolder, "/*", EnumSet.allOf(DispatcherType.class)); + + filterHolder = new FilterHolder(gitFilter); + context.addFilter(filterHolder, "/*", EnumSet.allOf(DispatcherType.class)); + } + +} diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/GitServlet.java b/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java similarity index 77% rename from gitop.core/src/main/java/com/pmease/gitop/core/GitServlet.java rename to gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java index f6e7f65ace..a0f878fe38 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/GitServlet.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java @@ -4,8 +4,12 @@ import java.io.IOException; import javax.inject.Inject; import javax.inject.Singleton; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -20,17 +24,16 @@ import com.pmease.gitop.core.manager.ProjectManager; import com.pmease.gitop.core.model.Project; @Singleton -@SuppressWarnings("serial") -public class GitServlet extends HttpServlet { +public class GitFilter implements Filter { - private static final Logger logger = LoggerFactory.getLogger(GitServlet.class); + private static final Logger logger = LoggerFactory.getLogger(GitFilter.class); private static final String INFO_REFS = "info/refs"; private final ProjectManager projectManager; @Inject - public GitServlet(ProjectManager projectManager) { + public GitFilter(ProjectManager projectManager) { this.projectManager = projectManager; } @@ -68,9 +71,7 @@ public class GitServlet extends HttpServlet { response.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate"); } - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String pathInfo = StringUtils.stripStart(req.getPathInfo(), "/"); + protected void processPacks(HttpServletRequest req, HttpServletResponse resp, String pathInfo) throws ServletException, IOException { String service = StringUtils.substringAfterLast(pathInfo, "/"); String repoInfo = StringUtils.substringBeforeLast(pathInfo, "/"); @@ -99,10 +100,7 @@ public class GitServlet extends HttpServlet { } } - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String pathInfo = StringUtils.stripStart(req.getPathInfo(), "/"); - + protected void processRefs(HttpServletRequest req, HttpServletResponse resp, String pathInfo) throws ServletException, IOException { if (!pathInfo.endsWith(INFO_REFS)) { String message = "Invalid refs request url: " + req.getRequestURL(); logger.error("Error serving git request: " + message); @@ -140,5 +138,32 @@ public class GitServlet extends HttpServlet { } } } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + + String pathInfo = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length()); + pathInfo = StringUtils.stripStart(pathInfo, "/"); + + if (pathInfo.endsWith(INFO_REFS)) { + processRefs(httpRequest, httpResponse, pathInfo); + } else if (pathInfo.endsWith("git-receive-pack") || pathInfo.endsWith("git-upload-pack")) { + processPacks(httpRequest, httpResponse, pathInfo); + } else { + chain.doFilter(request, response); + } + } + + @Override + public void destroy() { + } } + \ No newline at end of file diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/GitServletContextConfigurator.java b/gitop.core/src/main/java/com/pmease/gitop/core/GitServletContextConfigurator.java deleted file mode 100644 index d02ab8576b..0000000000 --- a/gitop.core/src/main/java/com/pmease/gitop/core/GitServletContextConfigurator.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.pmease.gitop.core; - -import javax.inject.Inject; - -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; - -import com.pmease.commons.jetty.ServletContextConfigurator; - -public class GitServletContextConfigurator implements ServletContextConfigurator { - - private final GitServlet gitServlet; - - @Inject - public GitServletContextConfigurator(GitServlet gitServlet) { - this.gitServlet = gitServlet; - } - - @Override - public void configure(ServletContextHandler context) { - ServletHolder servletHolder = new ServletHolder(gitServlet); - context.addServlet(servletHolder, "/git/*"); - } - -} diff --git a/gitop.product/pom.xml b/gitop.product/pom.xml index 8bb7145ba6..7a1a0d48ce 100644 --- a/gitop.product/pom.xml +++ b/gitop.product/pom.xml @@ -113,6 +113,11 @@ commons.jersey 1.0.30 + + com.pmease + gitop.rest + 1.0.0 + diff --git a/gitop.product/src/main/java/com/pmease/gitop/product/GitopServerConfigurator.java b/gitop.product/src/main/java/com/pmease/gitop/product/ProductConfigurator.java similarity index 89% rename from gitop.product/src/main/java/com/pmease/gitop/product/GitopServerConfigurator.java rename to gitop.product/src/main/java/com/pmease/gitop/product/ProductConfigurator.java index a281ffe830..4e37ff9de0 100644 --- a/gitop.product/src/main/java/com/pmease/gitop/product/GitopServerConfigurator.java +++ b/gitop.product/src/main/java/com/pmease/gitop/product/ProductConfigurator.java @@ -10,12 +10,12 @@ import com.pmease.commons.jetty.ServerConfigurator; import com.pmease.gitop.core.setting.ServerConfig; import com.pmease.gitop.core.setting.SslConfig; -public class GitopServerConfigurator implements ServerConfigurator { +public class ProductConfigurator implements ServerConfigurator { private ServerConfig serverConfig; @Inject - public GitopServerConfigurator(ServerConfig serverConfig) { + public ProductConfigurator(ServerConfig serverConfig) { this.serverConfig = serverConfig; } diff --git a/gitop.product/src/main/java/com/pmease/gitop/product/ProductModule.java b/gitop.product/src/main/java/com/pmease/gitop/product/ProductModule.java index 245bb6d68a..54e1ef93fe 100644 --- a/gitop.product/src/main/java/com/pmease/gitop/product/ProductModule.java +++ b/gitop.product/src/main/java/com/pmease/gitop/product/ProductModule.java @@ -6,7 +6,7 @@ import java.util.Properties; import com.google.inject.name.Names; import com.pmease.commons.bootstrap.Bootstrap; import com.pmease.commons.jetty.ServerConfigurator; -import com.pmease.commons.jetty.ServletContextConfigurator; +import com.pmease.commons.jetty.ServletConfigurator; import com.pmease.commons.loader.AbstractPluginModule; import com.pmease.commons.loader.AppName; import com.pmease.commons.util.FileUtils; @@ -30,8 +30,9 @@ public class ProductModule extends AbstractPluginModule { bind(ServerConfig.class).to(DefaultServerConfig.class); - contribute(ServerConfigurator.class, GitopServerConfigurator.class); - contribute(ServletContextConfigurator.class, GitopServletContextConfigurator.class); + contribute(ServerConfigurator.class, ProductConfigurator.class); + contribute(ServletConfigurator.class, ProductServletConfigurator.class); + } } diff --git a/gitop.product/src/main/java/com/pmease/gitop/product/GitopServletContextConfigurator.java b/gitop.product/src/main/java/com/pmease/gitop/product/ProductServletConfigurator.java similarity index 75% rename from gitop.product/src/main/java/com/pmease/gitop/product/GitopServletContextConfigurator.java rename to gitop.product/src/main/java/com/pmease/gitop/product/ProductServletConfigurator.java index a06b3b3f25..9b7c75371d 100644 --- a/gitop.product/src/main/java/com/pmease/gitop/product/GitopServletContextConfigurator.java +++ b/gitop.product/src/main/java/com/pmease/gitop/product/ProductServletConfigurator.java @@ -1,7 +1,5 @@ package com.pmease.gitop.product; -import java.io.File; - import javax.inject.Inject; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -9,15 +7,15 @@ import org.eclipse.jetty.servlet.ServletHolder; import com.pmease.commons.bootstrap.Bootstrap; import com.pmease.commons.jetty.FileAssetServlet; -import com.pmease.commons.jetty.ServletContextConfigurator; +import com.pmease.commons.jetty.ServletConfigurator; import com.pmease.gitop.core.setting.ServerConfig; -public class GitopServletContextConfigurator implements ServletContextConfigurator { +public class ProductServletConfigurator implements ServletConfigurator { private final ServerConfig serverConfig; @Inject - public GitopServletContextConfigurator(ServerConfig serverConfig) { + public ProductServletConfigurator(ServerConfig serverConfig) { this.serverConfig = serverConfig; } @@ -31,8 +29,7 @@ public class GitopServletContextConfigurator implements ServletContextConfigurat * Configure a servlet to serve contents under site folder. Site folder can be used * to hold site specific web assets. */ - File siteDir = new File(Bootstrap.installDir, "site"); - ServletHolder servletHolder = new ServletHolder(new FileAssetServlet(siteDir)); + ServletHolder servletHolder = new ServletHolder(new FileAssetServlet(Bootstrap.getSiteDir())); context.addServlet(servletHolder, "/site/*"); context.addServlet(servletHolder, "/robots.txt"); } diff --git a/gitop.rest/pom.xml b/gitop.rest/pom.xml new file mode 100644 index 0000000000..d2a246444e --- /dev/null +++ b/gitop.rest/pom.xml @@ -0,0 +1,57 @@ + + 4.0.0 + gitop.rest + 1.0.0 + + com.pmease + parent.general + 1.0.28 + + + + + + com.pmease + plugin.maven + + + maven-source-plugin + + + maven-javadoc-plugin + + + + + + + com.pmease + gitop.core + 1.0.30 + + + + + + pmeaseRepo + PMEase Repository + + true + never + fail + + + true + always + fail + + http://artifact.pmease.com/ + + + + + com.pmease.gitop.rest.RestModule + + + diff --git a/gitop.rest/src/main/java/com/pmease/gitop/rest/RestModule.java b/gitop.rest/src/main/java/com/pmease/gitop/rest/RestModule.java new file mode 100644 index 0000000000..ed0fd2221e --- /dev/null +++ b/gitop.rest/src/main/java/com/pmease/gitop/rest/RestModule.java @@ -0,0 +1,29 @@ +package com.pmease.gitop.rest; + +import org.apache.shiro.web.filter.mgt.FilterChainManager; + +import com.pmease.commons.loader.AbstractPluginModule; +import com.pmease.commons.shiro.FilterChainConfigurator; + +/** + * NOTE: Do not forget to rename moduleClass property defined in the pom if you've renamed this class. + * + */ +public class RestModule extends AbstractPluginModule { + + @Override + protected void configure() { + super.configure(); + + // put your guice bindings here + contribute(FilterChainConfigurator.class, new FilterChainConfigurator() { + + @Override + public void configure(FilterChainManager filterChainManager) { + filterChainManager.createChain("/rest/**", "noSessionCreation, authcBasic"); + } + + }); + } + +} diff --git a/gitop.web/pom.xml b/gitop.web/pom.xml index 31b60f1ae7..2f62ad7501 100644 --- a/gitop.web/pom.xml +++ b/gitop.web/pom.xml @@ -35,11 +35,6 @@ commons.wicket 1.0.29 - - com.pmease - commons.jersey - 1.0.30 - @@ -84,6 +79,11 @@ 0.7.0-SNAPSHOT + + com.pmease + commons.jetty + 1.0.29 + diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java b/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java index 21be234317..d1d074abd0 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java @@ -1,18 +1,10 @@ package com.pmease.gitop.web; import javax.inject.Singleton; -import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.servlet.ErrorPageErrorHandler; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; - -import com.pmease.commons.jetty.ClasspathAssetServlet; -import com.pmease.commons.jetty.ServletContextConfigurator; +import com.pmease.commons.jetty.ServletConfigurator; import com.pmease.commons.loader.AbstractPluginModule; import com.pmease.commons.wicket.AbstractWicketConfig; -import com.pmease.gitop.web.assets.AssetLocator; -import com.pmease.gitop.web.common.component.fileupload.FileUploadServlet; import com.pmease.gitop.web.resource.RestResourceModule; /** @@ -29,21 +21,7 @@ public class WebModule extends AbstractPluginModule { bind(AbstractWicketConfig.class).to(GitopWebApp.class); bind(SitePaths.class).in(Singleton.class); - contribute(ServletContextConfigurator.class, new ServletContextConfigurator() { - - @Override - public void configure(ServletContextHandler context) { - ServletHolder servletHolder = new ServletHolder(new ClasspathAssetServlet(AssetLocator.class)); - context.addServlet(servletHolder, "/assets/*"); - context.addServlet(servletHolder, "/favicon.ico"); - - ErrorPageErrorHandler errorHandler = (ErrorPageErrorHandler) context.getErrorHandler(); - errorHandler.addErrorPage(HttpServletResponse.SC_NOT_FOUND, "/assets/404.html"); - - servletHolder = context.addServlet(FileUploadServlet.class, "/uploads/*"); - } - - }); + contribute(ServletConfigurator.class, WebServletConfigurator.class); install(new RestResourceModule()); } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/WebServletConfigurator.java b/gitop.web/src/main/java/com/pmease/gitop/web/WebServletConfigurator.java new file mode 100644 index 0000000000..dfd3a7b49e --- /dev/null +++ b/gitop.web/src/main/java/com/pmease/gitop/web/WebServletConfigurator.java @@ -0,0 +1,47 @@ +package com.pmease.gitop.web; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.servlet.http.HttpServletResponse; + +import org.apache.wicket.protocol.http.WicketServlet; +import org.eclipse.jetty.servlet.ErrorPageErrorHandler; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +import com.pmease.commons.jetty.ClasspathAssetServlet; +import com.pmease.commons.jetty.ServletConfigurator; +import com.pmease.gitop.web.assets.AssetLocator; +import com.pmease.gitop.web.common.component.fileupload.FileUploadServlet; + +@Singleton +public class WebServletConfigurator implements ServletConfigurator { + + private final WicketServlet wicketServlet; + + @Inject + public WebServletConfigurator(WicketServlet wicketServlet) { + this.wicketServlet = wicketServlet; + } + + @Override + public void configure(ServletContextHandler context) { + ServletHolder servletHolder = new ServletHolder(wicketServlet); + + /* + * Add wicket servlet as the default servlet which will serve all requests failed to + * match a path pattern + */ + context.addServlet(servletHolder, "/"); + + servletHolder = new ServletHolder(new ClasspathAssetServlet(AssetLocator.class)); + context.addServlet(servletHolder, "/assets/*"); + context.addServlet(servletHolder, "/favicon.ico"); + + ErrorPageErrorHandler errorHandler = (ErrorPageErrorHandler) context.getErrorHandler(); + errorHandler.addErrorPage(HttpServletResponse.SC_NOT_FOUND, "/assets/404.html"); + + servletHolder = context.addServlet(FileUploadServlet.class, "/uploads/*"); + } + +} diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/WicketConfig.java b/gitop.web/src/main/java/com/pmease/gitop/web/WicketConfig.java deleted file mode 100644 index 181b5a412f..0000000000 --- a/gitop.web/src/main/java/com/pmease/gitop/web/WicketConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.pmease.gitop.web; - -import javax.inject.Singleton; - -import org.apache.wicket.Page; - -import com.pmease.commons.wicket.AbstractWicketConfig; -import com.pmease.gitop.web.page.home.HomePage; -import com.pmease.gitop.web.page.init.ServerInitPage; - -@Singleton -public class WicketConfig extends AbstractWicketConfig { - - @Override - protected void init() { - super.init(); - - mountPage("/", HomePage.class); - mountPage("/init", ServerInitPage.class); - - mountPage("/test/dudu", TestPage.class); - } - - @Override - public Class getHomePage() { - return HomePage.class; - } - -} From 0aab6f6089c381520a391c2e130d90b82f93dc50 Mon Sep 17 00:00:00 2001 From: robin shine Date: Tue, 1 Oct 2013 15:30:00 +0800 Subject: [PATCH 3/3] Github style account url, project url, and pull/push url. --- commons.editable/pom.xml | 27 ++++-- .../pmease/commons/editable/EditContext.java | 2 +- .../commons/editable/EditableUtils.java | 8 ++ .../commons/editable/NameValidator.java | 24 ++++++ .../pmease/commons/editable/PropertyPath.java | 4 +- .../commons/editable/annotation/Name.java | 36 ++++++++ .../hibernate/dao/AbstractGenericDao.java | 14 +++- .../commons/hibernate/dao/GenericDao.java | 8 +- .../com/pmease/commons/jetty/JettyModule.java | 5 ++ .../com/pmease/commons/jetty/JettyPlugin.java | 24 +++--- .../pmease/commons/wicket/WicketModule.java | 4 +- .../component/wizard/ManualConfigStep.java | 6 +- .../commons/wicket/editable/EditHelper.java | 29 ------- .../com/pmease/gitop/core/CoreModule.java | 26 ++++++ .../java/com/pmease/gitop/core/GitFilter.java | 3 + .../gitop/core/manager/ProjectManager.java | 10 ++- .../gitop/core/manager/UserManager.java | 8 +- .../manager/impl/DefaultProjectManager.java | 38 ++++++++- .../core/manager/impl/DefaultUserManager.java | 19 ++++- .../com/pmease/gitop/core/model/Project.java | 2 +- .../com/pmease/gitop/core/model/User.java | 5 +- .../gitop/core/validation/ProjectName.java | 24 ++++++ .../validation/ProjectNameReservation.java | 10 +++ .../core/validation/ProjectNameValidator.java | 22 +++++ .../gitop/core/validation/UserName.java | 24 ++++++ .../core/validation/UserNameReservation.java | 10 +++ .../core/validation/UserNameValidator.java | 22 +++++ .../com/pmease/gitop/web/GitopWebApp.java | 57 ++++++++++++- .../java/com/pmease/gitop/web/HomePage.html | 2 - .../java/com/pmease/gitop/web/TestPage.java | 7 +- .../java/com/pmease/gitop/web/WebModule.java | 2 + .../gitop/web/WebUserNameReservation.java | 64 ++++++++++++++ .../web/page/account/AccountHomePage.html | 2 + .../web/page/account/AccountHomePage.java | 63 ++++++++++++++ .../pmease/gitop/web/page/home/HomePage.html | 2 + .../pmease/gitop/web/page/home/HomePage.java | 10 +++ .../web/page/project/ProjectHomePage.html | 9 ++ .../web/page/project/ProjectHomePage.java | 84 +++++++++++++++++++ 38 files changed, 641 insertions(+), 75 deletions(-) create mode 100644 commons.editable/src/main/java/com/pmease/commons/editable/NameValidator.java create mode 100644 commons.editable/src/main/java/com/pmease/commons/editable/annotation/Name.java delete mode 100644 commons.wicket/src/main/java/com/pmease/commons/wicket/editable/EditHelper.java create mode 100644 gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectName.java create mode 100644 gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameReservation.java create mode 100644 gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameValidator.java create mode 100644 gitop.core/src/main/java/com/pmease/gitop/core/validation/UserName.java create mode 100644 gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameReservation.java create mode 100644 gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameValidator.java delete mode 100644 gitop.web/src/main/java/com/pmease/gitop/web/HomePage.html create mode 100644 gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java create mode 100644 gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.html create mode 100644 gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.java diff --git a/commons.editable/pom.xml b/commons.editable/pom.xml index 91ba186cbb..7823be2954 100644 --- a/commons.editable/pom.xml +++ b/commons.editable/pom.xml @@ -15,10 +15,9 @@ com.pmease plugin.maven - - + + maven-source-plugin @@ -34,11 +33,21 @@ commons.loader 1.0.29 - - org.hibernate - hibernate-validator - 5.0.1.Final - + + org.hibernate + hibernate-validator + 5.0.1.Final + + + javax.el + el-api + 2.2.1-b04 + + + org.glassfish.web + el-impl + 2.2.1-b05 + diff --git a/commons.editable/src/main/java/com/pmease/commons/editable/EditContext.java b/commons.editable/src/main/java/com/pmease/commons/editable/EditContext.java index 6be710cf48..364bd697eb 100644 --- a/commons.editable/src/main/java/com/pmease/commons/editable/EditContext.java +++ b/commons.editable/src/main/java/com/pmease/commons/editable/EditContext.java @@ -25,5 +25,5 @@ public interface EditContext extends Serializable { Object renderForEdit(Object renderParam); Object renderForView(Object renderParam); - + } diff --git a/commons.editable/src/main/java/com/pmease/commons/editable/EditableUtils.java b/commons.editable/src/main/java/com/pmease/commons/editable/EditableUtils.java index e65b4e4681..480396328a 100644 --- a/commons.editable/src/main/java/com/pmease/commons/editable/EditableUtils.java +++ b/commons.editable/src/main/java/com/pmease/commons/editable/EditableUtils.java @@ -139,4 +139,12 @@ public class EditableUtils { } } + public static EditContext getContext(Serializable bean) { + return AppLoader.getInstance(EditSupportRegistry.class).getBeanEditContext(bean); + } + + public static EditContext getContext(Serializable bean, String propertyName) { + return AppLoader.getInstance(EditSupportRegistry.class).getPropertyEditContext(bean, propertyName); + } + } diff --git a/commons.editable/src/main/java/com/pmease/commons/editable/NameValidator.java b/commons.editable/src/main/java/com/pmease/commons/editable/NameValidator.java new file mode 100644 index 0000000000..83698a5d33 --- /dev/null +++ b/commons.editable/src/main/java/com/pmease/commons/editable/NameValidator.java @@ -0,0 +1,24 @@ +package com.pmease.commons.editable; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import com.pmease.commons.editable.annotation.Name; +import com.pmease.commons.util.StringUtils; + +public class NameValidator implements ConstraintValidator { + + // insert spaces in invalid chars in order to get a pretty display for + // name validation error message. Refer to @Name annotation for more detail. + public static final String invalidChars = ", / \\ : * ? \" < > | [ ]"; + + public void initialize(Name constaintAnnotation) { + } + + public boolean isValid(String value, ConstraintValidatorContext constraintContext) { + if (value == null) + return true; + + return StringUtils.containsNone(value, StringUtils.deleteWhitespace(invalidChars)); + } +} diff --git a/commons.editable/src/main/java/com/pmease/commons/editable/PropertyPath.java b/commons.editable/src/main/java/com/pmease/commons/editable/PropertyPath.java index 165e10cf96..dad7c3a14c 100644 --- a/commons.editable/src/main/java/com/pmease/commons/editable/PropertyPath.java +++ b/commons.editable/src/main/java/com/pmease/commons/editable/PropertyPath.java @@ -25,13 +25,13 @@ public class PropertyPath implements Serializable { public PropertyPath prepend(Serializable element) { PropertyPath newPath = new PropertyPath(elements); newPath.elements.add(0, element); - return this; + return newPath; } public PropertyPath append(Serializable element) { PropertyPath newPath = new PropertyPath(elements); newPath.elements.add(element); - return this; + return newPath; } @Override diff --git a/commons.editable/src/main/java/com/pmease/commons/editable/annotation/Name.java b/commons.editable/src/main/java/com/pmease/commons/editable/annotation/Name.java new file mode 100644 index 0000000000..a7732f7534 --- /dev/null +++ b/commons.editable/src/main/java/com/pmease/commons/editable/annotation/Name.java @@ -0,0 +1,36 @@ +/* + * Copyright PMEase Inc., + * Date: 2008-2-28 + * All rights reserved. + * + * Revision: $Id: PathElement.java 1209 2008-07-28 00:16:18Z robin $ + */ +package com.pmease.commons.editable.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import org.hibernate.validator.constraints.NotEmpty; + +import com.pmease.commons.editable.NameValidator; + +/** + * @author robin + */ +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@NotEmpty +@Constraint(validatedBy=NameValidator.class) +public @interface Name { + String message() default "Name can not contain any of below characters:\n" + + NameValidator.invalidChars; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/dao/AbstractGenericDao.java b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/dao/AbstractGenericDao.java index 9d9b30fe06..5706d33a06 100644 --- a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/dao/AbstractGenericDao.java +++ b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/dao/AbstractGenericDao.java @@ -75,15 +75,25 @@ public abstract class AbstractGenericDao implements Ge } @Override - public List query(Criterion[] criterions) { + public List query(Criterion... criterions) { return query(criterions, null, 0, 0); } @Override - public T find(Criterion[] criterions) { + public List query() { + return query(new Criterion[0]); + } + + @Override + public T find(Criterion... criterions) { return find(criterions, null); } + @Override + public T find() { + return find(new Criterion[0]); + } + @SuppressWarnings("unchecked") @Override public T find(Criterion[] criterions, Order[] orders) { diff --git a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/dao/GenericDao.java b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/dao/GenericDao.java index e3826452b4..752c929ed1 100644 --- a/commons.hibernate/src/main/java/com/pmease/commons/hibernate/dao/GenericDao.java +++ b/commons.hibernate/src/main/java/com/pmease/commons/hibernate/dao/GenericDao.java @@ -76,7 +76,9 @@ public interface GenericDao { * @return * list of entity matching specified criterions. */ - List query(@Nullable Criterion[] criterions); + List query(Criterion... criterions); + + List query(); /** * This method expects to lookup a single entity with specified criteria. @@ -87,7 +89,9 @@ public interface GenericDao { * @return * any matching entity. null if not found */ - T find(@Nullable Criterion[] criterions); + T find(Criterion... criterions); + + T find(); /** * This method expects to find the first matching entity. diff --git a/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyModule.java b/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyModule.java index 0f3ffc0644..41b4fa62e0 100644 --- a/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyModule.java +++ b/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyModule.java @@ -5,6 +5,11 @@ import com.pmease.commons.loader.AbstractPluginModule; public class JettyModule extends AbstractPluginModule { + @Override + protected void configure() { + super.configure(); + } + @Override protected Class getPluginClass() { return JettyPlugin.class; diff --git a/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyPlugin.java b/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyPlugin.java index 41896b8cd4..89585435ce 100644 --- a/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyPlugin.java +++ b/commons.jetty/src/main/java/com/pmease/commons/jetty/JettyPlugin.java @@ -27,7 +27,7 @@ public class JettyPlugin extends AbstractPlugin { private Server server; - private ServletContextHandler context; + private ServletContextHandler contextHandler; private final Set serverConfigurators; @@ -61,32 +61,36 @@ public class JettyPlugin extends AbstractPlugin { } } - public ServletContextHandler getContext() { - return context; + public ServletContextHandler getContextHandler() { + return contextHandler; + } + + public Server getServer() { + return server; } private Server createServer() { server = new Server(); - context = new ServletContextHandler(ServletContextHandler.SESSIONS); + contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.setClassLoader(JettyPlugin.class.getClassLoader()); + contextHandler.setClassLoader(JettyPlugin.class.getClassLoader()); - context.setErrorHandler(new ErrorPageErrorHandler()); + contextHandler.setErrorHandler(new ErrorPageErrorHandler()); - context.addFilter(DisableTraceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); + contextHandler.addFilter(DisableTraceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); for (ServletConfigurator configurator: servletContextConfigurators) - configurator.configure(context); + configurator.configure(contextHandler); /* * Add Guice filter as last filter in order to make sure that filters and servlets * configured in Guice web module can be filtered correctly by filters added to * Jetty context directly. */ - context.addFilter(GuiceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); + contextHandler.addFilter(GuiceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); - server.setHandler(context); + server.setHandler(contextHandler); for (ServerConfigurator configurator: serverConfigurators) configurator.configure(server); diff --git a/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketModule.java b/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketModule.java index 27dbb5ff7d..1657e68490 100644 --- a/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketModule.java +++ b/commons.wicket/src/main/java/com/pmease/commons/wicket/WicketModule.java @@ -5,7 +5,7 @@ import org.apache.wicket.protocol.http.WicketServlet; import com.pmease.commons.editable.EditSupport; import com.pmease.commons.loader.AbstractPluginModule; -import com.pmease.commons.wicket.editable.EditHelper; +import com.pmease.commons.wicket.editable.EditableResourceReference; public class WicketModule extends AbstractPluginModule { @@ -16,7 +16,7 @@ public class WicketModule extends AbstractPluginModule { bind(WicketServlet.class).to(DefaultWicketServlet.class); bind(WicketFilter.class).to(DefaultWicketFilter.class); - contributeFromPackage(EditSupport.class, EditHelper.class); + contributeFromPackage(EditSupport.class, EditableResourceReference.class); } } diff --git a/commons.wicket/src/main/java/com/pmease/commons/wicket/component/wizard/ManualConfigStep.java b/commons.wicket/src/main/java/com/pmease/commons/wicket/component/wizard/ManualConfigStep.java index 3c71f48569..8c89a49dd2 100644 --- a/commons.wicket/src/main/java/com/pmease/commons/wicket/component/wizard/ManualConfigStep.java +++ b/commons.wicket/src/main/java/com/pmease/commons/wicket/component/wizard/ManualConfigStep.java @@ -3,8 +3,8 @@ package com.pmease.commons.wicket.component.wizard; import org.apache.wicket.Component; import com.pmease.commons.editable.EditContext; +import com.pmease.commons.editable.EditableUtils; import com.pmease.commons.util.init.ManualConfig; -import com.pmease.commons.wicket.editable.EditHelper; @SuppressWarnings("serial") public class ManualConfigStep implements WizardStep { @@ -15,12 +15,12 @@ public class ManualConfigStep implements WizardStep { public ManualConfigStep(ManualConfig config) { this.config = config; - editContext = EditHelper.getContext(config.getSetting()); + editContext = EditableUtils.getContext(config.getSetting()); } @Override public Component render(String componentId) { - return EditHelper.renderForEdit(editContext, componentId); + return (Component) editContext.renderForEdit(componentId); } @Override diff --git a/commons.wicket/src/main/java/com/pmease/commons/wicket/editable/EditHelper.java b/commons.wicket/src/main/java/com/pmease/commons/wicket/editable/EditHelper.java deleted file mode 100644 index ca3814ffd5..0000000000 --- a/commons.wicket/src/main/java/com/pmease/commons/wicket/editable/EditHelper.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.pmease.commons.wicket.editable; - -import java.io.Serializable; - -import org.apache.wicket.Component; - -import com.pmease.commons.editable.EditContext; -import com.pmease.commons.editable.EditSupportRegistry; -import com.pmease.commons.loader.AppLoader; - -public class EditHelper { - - public static EditContext getContext(Serializable bean) { - return AppLoader.getInstance(EditSupportRegistry.class).getBeanEditContext(bean); - } - - public static EditContext getContext(Serializable bean, String propertyName) { - return AppLoader.getInstance(EditSupportRegistry.class).getPropertyEditContext(bean, propertyName); - } - - public static Component renderForEdit(EditContext editContext, String componentId) { - return (Component) editContext.renderForEdit(componentId); - } - - public static Component renderForView(EditContext editContext, String componentId) { - return (Component) editContext.renderForView(componentId); - } - -} diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/CoreModule.java b/gitop.core/src/main/java/com/pmease/gitop/core/CoreModule.java index 0f36170e38..7dceeb65b5 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/CoreModule.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/CoreModule.java @@ -2,9 +2,11 @@ package com.pmease.gitop.core; import java.util.Collection; import java.util.HashSet; +import java.util.Set; import org.hibernate.cfg.NamingStrategy; +import com.google.common.collect.Sets; import com.pmease.commons.hibernate.AbstractEntity; import com.pmease.commons.hibernate.ModelProvider; import com.pmease.commons.hibernate.PrefixedNamingStrategy; @@ -15,6 +17,8 @@ import com.pmease.commons.shiro.AbstractRealm; import com.pmease.commons.util.ClassUtils; import com.pmease.gitop.core.model.ModelLocator; import com.pmease.gitop.core.permission.UserRealm; +import com.pmease.gitop.core.validation.ProjectNameReservation; +import com.pmease.gitop.core.validation.UserNameReservation; /** * NOTE: Do not forget to rename moduleClass property defined in the pom if you've renamed this class. @@ -43,6 +47,28 @@ public class CoreModule extends AbstractPluginModule { }); contribute(ServletConfigurator.class, CoreServletConfigurator.class); + + /* + * Contribute empty reservations to avoid Guice complain + */ + contribute(UserNameReservation.class, new UserNameReservation() { + + @Override + public Set getReserved() { + return Sets.newHashSet(); + } + }); + + /* + * Contribute empty reservations to avoid Guice complain + */ + contribute(ProjectNameReservation.class, new ProjectNameReservation() { + + @Override + public Set getReserved() { + return Sets.newHashSet(); + } + }); } @Override diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java b/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java index a0f878fe38..07a5777270 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java @@ -54,6 +54,9 @@ public class GitFilter implements Filter { return null; } + if (projectName.endsWith(".git")) + projectName = projectName.substring(0, projectName.length()-".git".length()); + Project project = projectManager.find(ownerName, projectName); if (project == null) { String message = "Unable to find project '" + projectName + "' owned by '" + ownerName + "'."; diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/manager/ProjectManager.java b/gitop.core/src/main/java/com/pmease/gitop/core/manager/ProjectManager.java index 7ed94af095..175611d886 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/manager/ProjectManager.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/manager/ProjectManager.java @@ -1,11 +1,15 @@ package com.pmease.gitop.core.manager; import java.util.Collection; +import java.util.Set; + +import javax.annotation.Nullable; import com.google.inject.ImplementedBy; import com.pmease.commons.hibernate.dao.GenericDao; import com.pmease.gitop.core.manager.impl.DefaultProjectManager; import com.pmease.gitop.core.model.Project; +import com.pmease.gitop.core.model.User; import com.pmease.gitop.core.storage.ProjectStorage; @ImplementedBy(DefaultProjectManager.class) @@ -13,7 +17,11 @@ public interface ProjectManager extends GenericDao { ProjectStorage locateStorage(Project project); - Project find(String ownerName, String projectName); + @Nullable Project find(String ownerName, String projectName); + @Nullable Project find(User owner, String projectName); + + Set getReservedNames(); + Collection findPublic(); } diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/manager/UserManager.java b/gitop.core/src/main/java/com/pmease/gitop/core/manager/UserManager.java index 94b921d3e3..515784163a 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/manager/UserManager.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/manager/UserManager.java @@ -1,5 +1,9 @@ package com.pmease.gitop.core.manager; +import java.util.Set; + +import javax.annotation.Nullable; + import com.google.inject.ImplementedBy; import com.pmease.commons.hibernate.dao.GenericDao; import com.pmease.commons.util.namedentity.EntityLoader; @@ -24,7 +28,9 @@ public interface UserManager extends GenericDao { * @return * matching user, or null if not found */ - User find(String userName); + @Nullable User find(String userName); + + Set getReservedNames(); EntityLoader asEntityLoader(); } diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/manager/impl/DefaultProjectManager.java b/gitop.core/src/main/java/com/pmease/gitop/core/manager/impl/DefaultProjectManager.java index 0fdb3b3a45..598d160dd3 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/manager/impl/DefaultProjectManager.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/manager/impl/DefaultProjectManager.java @@ -2,6 +2,8 @@ package com.pmease.gitop.core.manager.impl; import java.io.File; import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; @@ -11,24 +13,31 @@ import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Restrictions; import com.pmease.commons.git.Git; +import com.pmease.commons.hibernate.Sessional; import com.pmease.commons.hibernate.Transactional; import com.pmease.commons.hibernate.dao.AbstractGenericDao; import com.pmease.commons.hibernate.dao.GeneralDao; +import com.pmease.commons.util.FileUtils; import com.pmease.gitop.core.manager.ConfigManager; import com.pmease.gitop.core.manager.ProjectManager; import com.pmease.gitop.core.model.Project; +import com.pmease.gitop.core.model.User; import com.pmease.gitop.core.storage.ProjectStorage; +import com.pmease.gitop.core.validation.ProjectNameReservation; @Singleton public class DefaultProjectManager extends AbstractGenericDao implements ProjectManager { - private ConfigManager configManager; + private final ConfigManager configManager; + + private final Set nameReservations; @Inject - public DefaultProjectManager(GeneralDao generalDao, ConfigManager configManager) { + public DefaultProjectManager(GeneralDao generalDao, ConfigManager configManager, Set nameReservations) { super(generalDao); this.configManager = configManager; + this.nameReservations = nameReservations; } @Transactional @@ -40,8 +49,15 @@ public class DefaultProjectManager extends AbstractGenericDao implement ProjectStorage storage = locateStorage(entity); storage.clean(); - new Git(storage.ofCode()).init().bare(true).call(); + File codeDir = storage.ofCode(); + FileUtils.createDir(codeDir); + new Git(codeDir).init().bare(true).call(); } else { + File codeDir = locateStorage(entity).ofCode(); + if (!codeDir.exists()) { + FileUtils.createDir(codeDir); + new Git(codeDir).init().bare(true).call(); + } super.save(entity); } } @@ -64,6 +80,7 @@ public class DefaultProjectManager extends AbstractGenericDao implement return query(new Criterion[]{Restrictions.eq("publiclyAccessible", true)}); } + @Sessional @Override public Project find(String ownerName, String projectName) { Criteria criteria = createCriteria(); @@ -75,4 +92,19 @@ public class DefaultProjectManager extends AbstractGenericDao implement return (Project) criteria.uniqueResult(); } + @Override + public Set getReservedNames() { + Set reservedNames = new HashSet(); + for (ProjectNameReservation each: nameReservations) + reservedNames.addAll(each.getReserved()); + + return reservedNames; + } + + @Sessional + @Override + public Project find(User owner, String projectName) { + return find(Restrictions.eq("owner.id", owner.getId()), Restrictions.eq("name", projectName)); + } + } diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/manager/impl/DefaultUserManager.java b/gitop.core/src/main/java/com/pmease/gitop/core/manager/impl/DefaultUserManager.java index 73452d3e82..3482b9e822 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/manager/impl/DefaultUserManager.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/manager/impl/DefaultUserManager.java @@ -1,5 +1,8 @@ package com.pmease.gitop.core.manager.impl; +import java.util.HashSet; +import java.util.Set; + import javax.inject.Inject; import javax.inject.Singleton; @@ -15,15 +18,20 @@ import com.pmease.commons.util.namedentity.EntityLoader; import com.pmease.commons.util.namedentity.NamedEntity; import com.pmease.gitop.core.manager.UserManager; import com.pmease.gitop.core.model.User; +import com.pmease.gitop.core.validation.UserNameReservation; @Singleton public class DefaultUserManager extends AbstractGenericDao implements UserManager { private volatile Long rootUserId; + private final Set nameReservations; + @Inject - public DefaultUserManager(GeneralDao generalDao) { + public DefaultUserManager(GeneralDao generalDao, Set nameReservations) { super(generalDao); + + this.nameReservations = nameReservations; } @Sessional @@ -98,4 +106,13 @@ public class DefaultUserManager extends AbstractGenericDao implements User }; } + @Override + public Set getReservedNames() { + Set reservedNames = new HashSet(); + for (UserNameReservation each: nameReservations) + reservedNames.addAll(each.getReserved()); + + return reservedNames; + } + } diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/model/Project.java b/gitop.core/src/main/java/com/pmease/gitop/core/model/Project.java index c34bc1f03b..7ecdb5747e 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/model/Project.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/model/Project.java @@ -135,7 +135,7 @@ public class Project extends AbstractEntity implements UserBelonging { public Collection findAuthorizedUsers(GeneralOperation operation) { Set authorizedUsers = new HashSet(); - for (User user: Gitop.getInstance(UserManager.class).query(null)) { + for (User user: Gitop.getInstance(UserManager.class).query()) { if (user.asSubject().isPermitted(new ObjectPermission(this, operation))) authorizedUsers.add(user); } diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java b/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java index d63809f7c4..bac4a427b6 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java @@ -23,6 +23,7 @@ import com.pmease.gitop.core.permission.ObjectPermission; import com.pmease.gitop.core.permission.object.ProtectedObject; import com.pmease.gitop.core.permission.object.UserBelonging; import com.pmease.gitop.core.permission.operation.GeneralOperation; +import com.pmease.gitop.core.validation.UserName; @SuppressWarnings("serial") @Entity @@ -64,7 +65,7 @@ public class User extends AbstractUser implements ProtectedObject { private Collection voteVitations = new ArrayList(); @Editable(order=100) - @NotEmpty + @UserName @Override public String getName() { return super.getName(); @@ -223,7 +224,7 @@ public class User extends AbstractUser implements ProtectedObject { return true; } - for (Project each: Gitop.getInstance(ProjectManager.class).query(null)) { + for (Project each: Gitop.getInstance(ProjectManager.class).query()) { ObjectPermission projectPermission = new ObjectPermission(each, each.getDefaultAuthorizedOperation()); if (projectPermission.implies(objectPermission)) return true; diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectName.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectName.java new file mode 100644 index 0000000000..9d3add2db0 --- /dev/null +++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectName.java @@ -0,0 +1,24 @@ +package com.pmease.gitop.core.validation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import com.pmease.commons.editable.annotation.Name; + +@Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Name +@Constraint(validatedBy=ProjectNameValidator.class) +public @interface ProjectName { + + String message() default ""; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameReservation.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameReservation.java new file mode 100644 index 0000000000..c117beb799 --- /dev/null +++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameReservation.java @@ -0,0 +1,10 @@ +package com.pmease.gitop.core.validation; + +import java.util.Set; + +import com.pmease.commons.loader.ExtensionPoint; + +@ExtensionPoint +public interface ProjectNameReservation { + Set getReserved(); +} diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameValidator.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameValidator.java new file mode 100644 index 0000000000..8840e5c3a5 --- /dev/null +++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameValidator.java @@ -0,0 +1,22 @@ +package com.pmease.gitop.core.validation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import com.pmease.gitop.core.Gitop; +import com.pmease.gitop.core.manager.ProjectManager; + +public class ProjectNameValidator implements ConstraintValidator { + + public void initialize(ProjectName constaintAnnotation) { + } + + public boolean isValid(String value, ConstraintValidatorContext constraintContext) { + if (value == null) + return true; + + constraintContext.disableDefaultConstraintViolation(); + constraintContext.buildConstraintViolationWithTemplate(value + " is a reserved word.").addConstraintViolation(); + return !Gitop.getInstance(ProjectManager.class).getReservedNames().contains(value); + } +} diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserName.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserName.java new file mode 100644 index 0000000000..afc15eec8c --- /dev/null +++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserName.java @@ -0,0 +1,24 @@ +package com.pmease.gitop.core.validation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import com.pmease.commons.editable.annotation.Name; + +@Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Name +@Constraint(validatedBy=UserNameValidator.class) +public @interface UserName { + + String message() default ""; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameReservation.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameReservation.java new file mode 100644 index 0000000000..4c951a17cb --- /dev/null +++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameReservation.java @@ -0,0 +1,10 @@ +package com.pmease.gitop.core.validation; + +import java.util.Set; + +import com.pmease.commons.loader.ExtensionPoint; + +@ExtensionPoint +public interface UserNameReservation { + Set getReserved(); +} diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameValidator.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameValidator.java new file mode 100644 index 0000000000..c821a5d65f --- /dev/null +++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameValidator.java @@ -0,0 +1,22 @@ +package com.pmease.gitop.core.validation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import com.pmease.gitop.core.Gitop; +import com.pmease.gitop.core.manager.UserManager; + +public class UserNameValidator implements ConstraintValidator { + + public void initialize(UserName constaintAnnotation) { + } + + public boolean isValid(String value, ConstraintValidatorContext constraintContext) { + if (value == null) + return true; + + constraintContext.disableDefaultConstraintViolation(); + constraintContext.buildConstraintViolationWithTemplate(value + " is a reserved word.").addConstraintViolation(); + return !Gitop.getInstance(UserManager.class).getReservedNames().contains(value); + } +} diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java b/gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java index cdaaf0ebc8..23e170e285 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java @@ -2,23 +2,32 @@ package com.pmease.gitop.web; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import javax.inject.Singleton; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.wicket.Application; import org.apache.wicket.Page; import org.apache.wicket.Session; import org.apache.wicket.bean.validation.BeanValidationConfiguration; +import org.apache.wicket.core.request.mapper.MountedMapper; +import org.apache.wicket.request.IRequestMapper; import org.apache.wicket.request.Request; import org.apache.wicket.request.Response; +import org.apache.wicket.request.Url; import org.apache.wicket.util.time.Duration; import org.apache.wicket.util.time.Time; import com.google.common.base.Throwables; import com.google.common.io.ByteStreams; import com.pmease.commons.wicket.AbstractWicketConfig; +import com.pmease.gitop.core.Gitop; +import com.pmease.gitop.core.manager.ProjectManager; +import com.pmease.gitop.core.manager.UserManager; import com.pmease.gitop.web.assets.AssetLocator; import com.pmease.gitop.web.common.component.avatar.AvatarImageResource; import com.pmease.gitop.web.common.component.avatar.AvatarImageResourceReference; @@ -30,6 +39,7 @@ import com.pmease.gitop.web.page.account.setting.profile.AccountProfilePage; import com.pmease.gitop.web.page.account.setting.repos.AccountReposPage; import com.pmease.gitop.web.page.home.HomePage; import com.pmease.gitop.web.page.init.ServerInitPage; +import com.pmease.gitop.web.page.project.ProjectHomePage; import com.pmease.gitop.web.shiro.LoginPage; import com.pmease.gitop.web.shiro.LogoutPage; import com.pmease.gitop.web.shiro.ShiroWicketPlugin; @@ -110,19 +120,60 @@ public class GitopWebApp extends AbstractWicketConfig { // account related pages // -------------------------------------------------------- + // project dashboard + mount(new MountedMapper("/${user}/${project}", ProjectHomePage.class) { + + @Override + protected boolean urlStartsWith(Url url, String... segments) { + List normalizedSegments = normalizeUrlSegments(url.getSegments()); + if (normalizedSegments.size() < 2) + return false; + String userName = normalizedSegments.get(0); + if (Gitop.getInstance(UserManager.class).getReservedNames().contains(userName)) + return false; + + String projectName = normalizedSegments.get(1); + return !Gitop.getInstance(ProjectManager.class).getReservedNames().contains(projectName); + } + + }); + // account dashboard - mountPage("account/${user}", AccountHomePage.class); + mount(new MountedMapper("/${user}", AccountHomePage.class) { + + @Override + protected boolean urlStartsWith(Url url, String... segments) { + List normalizedSegments = normalizeUrlSegments(url.getSegments()); + if (normalizedSegments.size() < 1) + return false; + String userName = normalizedSegments.get(0); + return !Gitop.getInstance(UserManager.class).getReservedNames().contains(userName); + } + + }); // account settings mountPage("settings/profile", AccountProfilePage.class); mountPage("settings/password", AccountPasswordPage.class); mountPage("settings/permission", AccountPermissionPage.class); mountPage("settings/repos", AccountReposPage.class); + + mountPage("/test", TestPage.class); // repository pages // -------------------------------------------------------- } + + private List normalizeUrlSegments(List segments) { + List normalized = new ArrayList(); + for (String each: segments) { + each = StringUtils.remove(each, '/'); + if (each.length() != 0) + normalized.add(each); + } + return normalized; + } private void mountResources() { getSharedResources().add(AvatarImageResourceReference.AVATAR_RESOURCE, new AvatarImageResource()); @@ -139,4 +190,8 @@ public class GitopWebApp extends AbstractWicketConfig { public boolean isPublicSignupEnabled() { return true; } + + public Iterable getRequestMappers() { + return getRootRequestMapperAsCompound(); + } } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/HomePage.html b/gitop.web/src/main/java/com/pmease/gitop/web/HomePage.html deleted file mode 100644 index b47194918b..0000000000 --- a/gitop.web/src/main/java/com/pmease/gitop/web/HomePage.html +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java b/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java index ec81fcfcb6..1266a6643c 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java @@ -1,9 +1,10 @@ package com.pmease.gitop.web; +import org.apache.wicket.Component; import org.apache.wicket.markup.html.form.Form; import com.pmease.commons.editable.EditContext; -import com.pmease.commons.wicket.editable.EditHelper; +import com.pmease.commons.editable.EditableUtils; import com.pmease.gitop.core.Gitop; import com.pmease.gitop.core.manager.ProjectManager; import com.pmease.gitop.core.manager.UserManager; @@ -17,7 +18,7 @@ public class TestPage extends BasePage { protected void onInitialize() { super.onInitialize(); - final EditContext editContext = EditHelper.getContext(new Project()); + final EditContext editContext = EditableUtils.getContext(new Project()); Form form = new Form("form") { @@ -34,7 +35,7 @@ public class TestPage extends BasePage { }; - form.add(EditHelper.renderForEdit(editContext, "editor")); + form.add((Component)editContext.renderForEdit("editor")); add(form); } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java b/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java index d1d074abd0..f48ca2d7a2 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java @@ -5,6 +5,7 @@ import javax.inject.Singleton; import com.pmease.commons.jetty.ServletConfigurator; import com.pmease.commons.loader.AbstractPluginModule; import com.pmease.commons.wicket.AbstractWicketConfig; +import com.pmease.gitop.core.validation.UserNameReservation; import com.pmease.gitop.web.resource.RestResourceModule; /** @@ -22,6 +23,7 @@ public class WebModule extends AbstractPluginModule { bind(SitePaths.class).in(Singleton.class); contribute(ServletConfigurator.class, WebServletConfigurator.class); + contribute(UserNameReservation.class, WebUserNameReservation.class); install(new RestResourceModule()); } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java b/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java new file mode 100644 index 0000000000..df8e520b32 --- /dev/null +++ b/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java @@ -0,0 +1,64 @@ +package com.pmease.gitop.web; + +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.commons.lang3.StringUtils; +import org.apache.wicket.core.request.mapper.MountedMapper; +import org.apache.wicket.core.request.mapper.ResourceMapper; +import org.apache.wicket.request.IRequestMapper; +import org.eclipse.jetty.servlet.ServletMapping; + +import com.google.common.base.Preconditions; +import com.pmease.commons.jetty.JettyPlugin; +import com.pmease.commons.util.ReflectionUtils; +import com.pmease.gitop.core.validation.UserNameReservation; + +public class WebUserNameReservation implements UserNameReservation { + + private final JettyPlugin jettyPlugin; + + private final GitopWebApp webApp; + + @Inject + public WebUserNameReservation(JettyPlugin jettyPlugin, GitopWebApp webApp) { + this.jettyPlugin = jettyPlugin; + this.webApp = webApp; + } + + @Override + public Set getReserved() { + Set reserved = new HashSet(); + for (ServletMapping mapping: jettyPlugin.getContextHandler().getServletHandler().getServletMappings()) { + for (String pathSpec: mapping.getPathSpecs()) { + pathSpec = StringUtils.stripStart(pathSpec, "/"); + pathSpec = StringUtils.substringBefore(pathSpec, "/"); + if (pathSpec.trim().length() != 0) + reserved.add(pathSpec.trim()); + } + } + + reserved.add("wicket"); + + for (IRequestMapper mapper: webApp.getRequestMappers()) { + if (mapper instanceof MountedMapper || mapper instanceof ResourceMapper) { + try { + Field field = ReflectionUtils.findField(mapper.getClass(), "mountSegments"); + Preconditions.checkNotNull(field); + field.setAccessible(true); + String[] mountSegments = (String[]) field.get(mapper); + if (mountSegments != null && mountSegments.length != 0 && mountSegments[0] != null) + reserved.add(mountSegments[0]); + } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + + return reserved; + } + +} diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.html b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.html index 98b2a00836..3a84612183 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.html +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.html @@ -1,5 +1,7 @@

Welcome, Account home

+
+ link \ No newline at end of file diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java index 4fa3fe15d9..b3d5b5bcd0 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java @@ -1,16 +1,79 @@ package com.pmease.gitop.web.page.account; import org.apache.shiro.authz.annotation.RequiresAuthentication; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.link.Link; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import com.pmease.commons.util.GeneralException; +import com.pmease.gitop.core.Gitop; +import com.pmease.gitop.core.manager.UserManager; +import com.pmease.gitop.core.model.User; import com.pmease.gitop.web.page.AbstractLayoutPage; @SuppressWarnings("serial") @RequiresAuthentication public class AccountHomePage extends AbstractLayoutPage { + private final IModel accountModel; + + public AccountHomePage(PageParameters params) { + String accountName = params.get("user").toString(); + + User account = Gitop.getInstance(UserManager.class).find(accountName); + if (account == null) + throw new GeneralException("Account %s does not exist!", accountName); + + final Long accountId = account.getId(); + + accountModel = new LoadableDetachableModel() { + + @Override + protected User load() { + return Gitop.getInstance(UserManager.class).load(accountId); + } + + }; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + add(new Label("accountName", getAccount().getName())); + + add(new Link("link") { + + @Override + public void onClick() { + + } + + }); + } + @Override protected String getPageTitle() { return "Gitop"; } + public User getAccount() { + return accountModel.getObject(); + } + + @Override + public void detachModels() { + accountModel.detach(); + + super.detachModels(); + } + + public static PageParameters paramsOf(User account) { + PageParameters params = new PageParameters(); + params.set("user", account.getName()); + return params; + } + } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html index f0be37e899..71c2188950 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html @@ -5,5 +5,7 @@

Upload Test

+ account + project \ No newline at end of file diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.java index 03965cd373..5efee2a736 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.java @@ -1,7 +1,14 @@ package com.pmease.gitop.web.page.home; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; + +import com.pmease.gitop.core.Gitop; +import com.pmease.gitop.core.manager.ProjectManager; +import com.pmease.gitop.core.manager.UserManager; import com.pmease.gitop.web.common.component.fileupload.FileUploadBar; import com.pmease.gitop.web.page.AbstractLayoutPage; +import com.pmease.gitop.web.page.account.AccountHomePage; +import com.pmease.gitop.web.page.project.ProjectHomePage; public class HomePage extends AbstractLayoutPage { @@ -17,5 +24,8 @@ public class HomePage extends AbstractLayoutPage { super.onInitialize(); add(new FileUploadBar("upload")); + + add(new BookmarkablePageLink<>("accountLink", AccountHomePage.class, AccountHomePage.paramsOf(Gitop.getInstance(UserManager.class).getRootUser()))); + add(new BookmarkablePageLink<>("projectLink", ProjectHomePage.class, ProjectHomePage.paramsOf(Gitop.getInstance(ProjectManager.class).load(1L)))); } } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.html b/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.html new file mode 100644 index 0000000000..3d08112ea0 --- /dev/null +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.html @@ -0,0 +1,9 @@ + + +

Welcome, Project Home

+
+
+ + link +
+ \ No newline at end of file diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.java new file mode 100644 index 0000000000..77295e700d --- /dev/null +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.java @@ -0,0 +1,84 @@ +package com.pmease.gitop.web.page.project; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.link.Link; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +import com.pmease.commons.util.GeneralException; +import com.pmease.gitop.core.Gitop; +import com.pmease.gitop.core.manager.ProjectManager; +import com.pmease.gitop.core.model.Project; +import com.pmease.gitop.web.page.AbstractLayoutPage; + +@SuppressWarnings("serial") +public class ProjectHomePage extends AbstractLayoutPage { + + private final IModel projectModel; + + @Override + protected String getPageTitle() { + return "Project Home"; + } + + public ProjectHomePage(PageParameters params) { + String userName = params.get("user").toString(); + String projectName = params.get("project").toString(); + + if (projectName.endsWith(".git")) + projectName = projectName.substring(0, projectName.length() - ".git".length()); + + Project project = Gitop.getInstance(ProjectManager.class).find(userName, projectName); + + if (project == null) + throw new GeneralException("Can not find project %s under account %s.", projectName, userName); + + final Long projectId = project.getId(); + + projectModel = new LoadableDetachableModel() { + + @Override + protected Project load() { + return Gitop.getInstance(ProjectManager.class).load(projectId); + } + + }; + + add(new Link("link") { + + @Override + public void onClick() { + + } + + }); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + add(new Label("accountName", getProject().getOwner().getName())); + add(new Label("projectName", getProject().getName())); + } + + public Project getProject() { + return projectModel.getObject(); + } + + @Override + public void detachModels() { + projectModel.detach(); + super.detachModels(); + } + + public static PageParameters paramsOf(Project project) { + PageParameters params = new PageParameters(); + params.set("user", project.getOwner().getName()); + params.set("project", project.getName()); + + return params; + } + +}