Conflicts:
	gitop.web/pom.xml
	gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java
	gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java
	gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java
	gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.java
	gitop.web/src/main/java/com/pmease/gitop/web/resource/TestResource.java
This commit is contained in:
steve 2013-10-01 20:25:08 +08:00
commit 4b10ee989f
65 changed files with 965 additions and 380 deletions

View File

@ -15,10 +15,9 @@
<groupId>com.pmease</groupId> <groupId>com.pmease</groupId>
<artifactId>plugin.maven</artifactId> <artifactId>plugin.maven</artifactId>
</plugin> </plugin>
<!-- Uncomment below if you'd like to publish an archetype based on your plugin --> <!-- Uncomment below if you'd like to publish an archetype based on your
<!--plugin> plugin -->
<artifactId>maven-archetype-plugin</artifactId> <!--plugin> <artifactId>maven-archetype-plugin</artifactId> </plugin -->
</plugin-->
<plugin> <plugin>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
</plugin> </plugin>
@ -39,6 +38,16 @@
<artifactId>hibernate-validator</artifactId> <artifactId>hibernate-validator</artifactId>
<version>5.0.1.Final</version> <version>5.0.1.Final</version>
</dependency> </dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>2.2.1-b04</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>el-impl</artifactId>
<version>2.2.1-b05</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>

View File

@ -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);
}
} }

View File

@ -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<Name, String> {
// 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));
}
}

View File

@ -25,13 +25,13 @@ public class PropertyPath implements Serializable {
public PropertyPath prepend(Serializable element) { public PropertyPath prepend(Serializable element) {
PropertyPath newPath = new PropertyPath(elements); PropertyPath newPath = new PropertyPath(elements);
newPath.elements.add(0, element); newPath.elements.add(0, element);
return this; return newPath;
} }
public PropertyPath append(Serializable element) { public PropertyPath append(Serializable element) {
PropertyPath newPath = new PropertyPath(elements); PropertyPath newPath = new PropertyPath(elements);
newPath.elements.add(element); newPath.elements.add(element);
return this; return newPath;
} }
@Override @Override

View File

@ -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<? extends Payload>[] payload() default {};
}

View File

@ -43,11 +43,6 @@
<artifactId>commons.util</artifactId> <artifactId>commons.util</artifactId>
<version>1.0.29</version> <version>1.0.29</version>
</dependency> </dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>commons.jetty</artifactId>
<version>1.0.29</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>

View File

@ -76,11 +76,6 @@
<artifactId>jtds</artifactId> <artifactId>jtds</artifactId>
<version>1.3.0</version> <version>1.3.0</version>
</dependency> </dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>commons.jetty</artifactId>
<version>1.0.29</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>
<repository> <repository>

View File

@ -65,4 +65,9 @@ public class DefaultUnitOfWork implements UnitOfWork, Provider<Session> {
return sessionFactoryProvider.get(); return sessionFactoryProvider.get();
} }
@Override
public void reset() {
sessionReferenceHolder.get().reset();
}
} }

View File

@ -13,7 +13,6 @@ import com.google.inject.name.Names;
import com.google.inject.util.Providers; import com.google.inject.util.Providers;
import com.pmease.commons.hibernate.dao.DefaultGeneralDao; import com.pmease.commons.hibernate.dao.DefaultGeneralDao;
import com.pmease.commons.hibernate.dao.GeneralDao; import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.commons.jetty.ServletContextConfigurator;
import com.pmease.commons.loader.AbstractPlugin; import com.pmease.commons.loader.AbstractPlugin;
import com.pmease.commons.loader.AbstractPluginModule; import com.pmease.commons.loader.AbstractPluginModule;
@ -51,8 +50,6 @@ public class HibernateModule extends AbstractPluginModule {
Matchers.any(), Matchers.any(),
Matchers.annotatedWith(Sessional.class), Matchers.annotatedWith(Sessional.class),
sessionInterceptor); sessionInterceptor);
contribute(ServletContextConfigurator.class, HibernateServletContextConfigurator.class);
} }
@Override @Override

View File

@ -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));
}
}

View File

@ -25,6 +25,8 @@ public interface UnitOfWork {
void end(); void end();
void reset();
Session getSession(); Session getSession();
SessionFactory getSessionFactory(); SessionFactory getSessionFactory();

View File

@ -75,15 +75,25 @@ public abstract class AbstractGenericDao<T extends AbstractEntity> implements Ge
} }
@Override @Override
public List<T> query(Criterion[] criterions) { public List<T> query(Criterion... criterions) {
return query(criterions, null, 0, 0); return query(criterions, null, 0, 0);
} }
@Override @Override
public T find(Criterion[] criterions) { public List<T> query() {
return query(new Criterion[0]);
}
@Override
public T find(Criterion... criterions) {
return find(criterions, null); return find(criterions, null);
} }
@Override
public T find() {
return find(new Criterion[0]);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public T find(Criterion[] criterions, Order[] orders) { public T find(Criterion[] criterions, Order[] orders) {

View File

@ -76,7 +76,9 @@ public interface GenericDao<T extends AbstractEntity> {
* @return * @return
* list of entity matching specified criterions. * list of entity matching specified criterions.
*/ */
List<T> query(@Nullable Criterion[] criterions); List<T> query(Criterion... criterions);
List<T> query();
/** /**
* This method expects to lookup a single entity with specified criteria. * This method expects to lookup a single entity with specified criteria.
@ -87,7 +89,9 @@ public interface GenericDao<T extends AbstractEntity> {
* @return * @return
* any matching entity. null if not found * 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. * This method expects to find the first matching entity.

View File

@ -43,11 +43,6 @@
<artifactId>jersey-guice</artifactId> <artifactId>jersey-guice</artifactId>
<version>${jerseyVersion}</version> <version>${jerseyVersion}</version>
</dependency> </dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>commons.shiro</artifactId>
<version>1.0.30</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>
<repository> <repository>

View File

@ -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.";
}
}

View File

@ -1,12 +1,6 @@
package com.pmease.commons.jersey; package com.pmease.commons.jersey;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import com.pmease.commons.loader.AbstractPluginModule; 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 * 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 class JerseyModule extends AbstractPluginModule {
public static final String REST_PATH = "rest";
@Override @Override
protected void configure() { protected void configure() {
super.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");
}
});
} }
} }

View File

@ -5,6 +5,11 @@ import com.pmease.commons.loader.AbstractPluginModule;
public class JettyModule extends AbstractPluginModule { public class JettyModule extends AbstractPluginModule {
@Override
protected void configure() {
super.configure();
}
@Override @Override
protected Class<? extends AbstractPlugin> getPluginClass() { protected Class<? extends AbstractPlugin> getPluginClass() {
return JettyPlugin.class; return JettyPlugin.class;

View File

@ -27,16 +27,16 @@ public class JettyPlugin extends AbstractPlugin {
private Server server; private Server server;
private ServletContextHandler context; private ServletContextHandler contextHandler;
private final Set<ServerConfigurator> serverConfigurators; private final Set<ServerConfigurator> serverConfigurators;
private final Set<ServletContextConfigurator> servletContextConfigurators; private final Set<ServletConfigurator> servletContextConfigurators;
@Inject @Inject
public JettyPlugin( public JettyPlugin(
Set<ServerConfigurator> serverConfigurators, Set<ServerConfigurator> serverConfigurators,
Set<ServletContextConfigurator> servletContextConfigurators) { Set<ServletConfigurator> servletContextConfigurators) {
this.serverConfigurators = serverConfigurators; this.serverConfigurators = serverConfigurators;
this.servletContextConfigurators = servletContextConfigurators; this.servletContextConfigurators = servletContextConfigurators;
} }
@ -61,32 +61,36 @@ public class JettyPlugin extends AbstractPlugin {
} }
} }
public ServletContextHandler getContext() { public ServletContextHandler getContextHandler() {
return context; return contextHandler;
}
public Server getServer() {
return server;
} }
private Server createServer() { private Server createServer() {
server = new Server(); 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 (ServletContextConfigurator configurator: servletContextConfigurators) 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 * 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 * configured in Guice web module can be filtered correctly by filters added to
* Jetty context directly. * 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) for (ServerConfigurator configurator: serverConfigurators)
configurator.configure(server); configurator.configure(server);

View File

@ -5,6 +5,6 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
import com.pmease.commons.loader.ExtensionPoint; import com.pmease.commons.loader.ExtensionPoint;
@ExtensionPoint @ExtensionPoint
public interface ServletContextConfigurator { public interface ServletConfigurator {
void configure(ServletContextHandler context); void configure(ServletContextHandler context);
} }

View File

@ -38,11 +38,6 @@
<artifactId>shiro-web</artifactId> <artifactId>shiro-web</artifactId>
<version>${shiroVersion}</version> <version>${shiroVersion}</version>
</dependency> </dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>commons.jetty</artifactId>
<version>1.0.29</version>
</dependency>
<dependency> <dependency>
<groupId>com.pmease</groupId> <groupId>com.pmease</groupId>
<artifactId>commons.hibernate</artifactId> <artifactId>commons.hibernate</artifactId>

View File

@ -1,23 +1,15 @@
package com.pmease.commons.shiro; package com.pmease.commons.shiro;
import java.util.EnumSet;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.servlet.DispatcherType;
import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.DefaultPasswordService; import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.authc.credential.PasswordService; import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.guice.aop.ShiroAopModule; 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.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.mgt.WebSecurityManager; import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.ShiroFilter; 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; import com.pmease.commons.loader.AbstractPluginModule;
/** /**
@ -36,23 +28,9 @@ public class ShiroModule extends AbstractPluginModule {
bind(BasicAuthenticationFilter.class); bind(BasicAuthenticationFilter.class);
bind(PasswordService.class).to(DefaultPasswordService.class).in(Singleton.class); bind(PasswordService.class).to(DefaultPasswordService.class).in(Singleton.class);
bind(CredentialsMatcher.class).to(DefaultPasswordMatcher.class); bind(CredentialsMatcher.class).to(DefaultPasswordMatcher.class);
bind(ShiroFilter.class);
install(new ShiroAopModule()); 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));
}
});
} }
} }

View File

@ -36,5 +36,13 @@ public abstract class ObjectReference<T> {
} }
} }
public synchronized void reset() {
count = 0;
if (object != null) {
closeObject(object);
object = null;
}
}
protected abstract void closeObject(T object); protected abstract void closeObject(T object);
} }

View File

@ -53,11 +53,6 @@
<artifactId>commons.loader</artifactId> <artifactId>commons.loader</artifactId>
<version>1.0.29</version> <version>1.0.29</version>
</dependency> </dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>commons.jetty</artifactId>
<version>1.0.29</version>
</dependency>
<dependency> <dependency>
<groupId>com.pmease</groupId> <groupId>com.pmease</groupId>
<artifactId>commons.editable</artifactId> <artifactId>commons.editable</artifactId>

View File

@ -4,9 +4,8 @@ import org.apache.wicket.protocol.http.WicketFilter;
import org.apache.wicket.protocol.http.WicketServlet; import org.apache.wicket.protocol.http.WicketServlet;
import com.pmease.commons.editable.EditSupport; import com.pmease.commons.editable.EditSupport;
import com.pmease.commons.jetty.ServletContextConfigurator;
import com.pmease.commons.loader.AbstractPluginModule; 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 { public class WicketModule extends AbstractPluginModule {
@ -17,9 +16,7 @@ public class WicketModule extends AbstractPluginModule {
bind(WicketServlet.class).to(DefaultWicketServlet.class); bind(WicketServlet.class).to(DefaultWicketServlet.class);
bind(WicketFilter.class).to(DefaultWicketFilter.class); bind(WicketFilter.class).to(DefaultWicketFilter.class);
contribute(ServletContextConfigurator.class, WicketServletContextConfigurator.class); contributeFromPackage(EditSupport.class, EditableResourceReference.class);
contributeFromPackage(EditSupport.class, EditHelper.class);
} }
} }

View File

@ -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, "/");
}
}

View File

@ -3,8 +3,8 @@ package com.pmease.commons.wicket.component.wizard;
import org.apache.wicket.Component; import org.apache.wicket.Component;
import com.pmease.commons.editable.EditContext; import com.pmease.commons.editable.EditContext;
import com.pmease.commons.editable.EditableUtils;
import com.pmease.commons.util.init.ManualConfig; import com.pmease.commons.util.init.ManualConfig;
import com.pmease.commons.wicket.editable.EditHelper;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class ManualConfigStep implements WizardStep { public class ManualConfigStep implements WizardStep {
@ -15,12 +15,12 @@ public class ManualConfigStep implements WizardStep {
public ManualConfigStep(ManualConfig config) { public ManualConfigStep(ManualConfig config) {
this.config = config; this.config = config;
editContext = EditHelper.getContext(config.getSetting()); editContext = EditableUtils.getContext(config.getSetting());
} }
@Override @Override
public Component render(String componentId) { public Component render(String componentId) {
return EditHelper.renderForEdit(editContext, componentId); return (Component) editContext.renderForEdit(componentId);
} }
@Override @Override

View File

@ -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);
}
}

View File

@ -46,6 +46,11 @@
<artifactId>commons.editable</artifactId> <artifactId>commons.editable</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>commons.jetty</artifactId>
<version>1.0.29</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>
<repository> <repository>
@ -65,7 +70,7 @@
</repository> </repository>
</repositories> </repositories>
<properties> <properties>
<moduleClass>com.pmease.gitop.core.GitopModule</moduleClass> <moduleClass>com.pmease.gitop.core.CoreModule</moduleClass>
</properties> </properties>
<version>1.0.30</version> <version>1.0.30</version>
</project> </project>

View File

@ -2,25 +2,29 @@ package com.pmease.gitop.core;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set;
import org.hibernate.cfg.NamingStrategy; import org.hibernate.cfg.NamingStrategy;
import com.google.common.collect.Sets;
import com.pmease.commons.hibernate.AbstractEntity; import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.commons.hibernate.ModelProvider; import com.pmease.commons.hibernate.ModelProvider;
import com.pmease.commons.hibernate.PrefixedNamingStrategy; 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.AbstractPlugin;
import com.pmease.commons.loader.AbstractPluginModule; import com.pmease.commons.loader.AbstractPluginModule;
import com.pmease.commons.shiro.AbstractRealm; import com.pmease.commons.shiro.AbstractRealm;
import com.pmease.commons.util.ClassUtils; import com.pmease.commons.util.ClassUtils;
import com.pmease.gitop.core.model.ModelLocator; import com.pmease.gitop.core.model.ModelLocator;
import com.pmease.gitop.core.permission.UserRealm; 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. * 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 @Override
protected void configure() { protected void configure() {
@ -42,7 +46,29 @@ public class GitopModule extends AbstractPluginModule {
}); });
contribute(ServletContextConfigurator.class, GitServletContextConfigurator.class); contribute(ServletConfigurator.class, CoreServletConfigurator.class);
/*
* Contribute empty reservations to avoid Guice complain
*/
contribute(UserNameReservation.class, new UserNameReservation() {
@Override
public Set<String> getReserved() {
return Sets.newHashSet();
}
});
/*
* Contribute empty reservations to avoid Guice complain
*/
contribute(ProjectNameReservation.class, new ProjectNameReservation() {
@Override
public Set<String> getReserved() {
return Sets.newHashSet();
}
});
} }
@Override @Override

View File

@ -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));
}
}

View File

@ -4,8 +4,12 @@ import java.io.IOException;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException; 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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -20,17 +24,16 @@ import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.model.Project; import com.pmease.gitop.core.model.Project;
@Singleton @Singleton
@SuppressWarnings("serial") public class GitFilter implements Filter {
public class GitServlet extends HttpServlet {
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 static final String INFO_REFS = "info/refs";
private final ProjectManager projectManager; private final ProjectManager projectManager;
@Inject @Inject
public GitServlet(ProjectManager projectManager) { public GitFilter(ProjectManager projectManager) {
this.projectManager = projectManager; this.projectManager = projectManager;
} }
@ -51,6 +54,9 @@ public class GitServlet extends HttpServlet {
return null; return null;
} }
if (projectName.endsWith(".git"))
projectName = projectName.substring(0, projectName.length()-".git".length());
Project project = projectManager.find(ownerName, projectName); Project project = projectManager.find(ownerName, projectName);
if (project == null) { if (project == null) {
String message = "Unable to find project '" + projectName + "' owned by '" + ownerName + "'."; String message = "Unable to find project '" + projectName + "' owned by '" + ownerName + "'.";
@ -68,9 +74,7 @@ public class GitServlet extends HttpServlet {
response.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate"); response.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate");
} }
@Override protected void processPacks(HttpServletRequest req, HttpServletResponse resp, String pathInfo) throws ServletException, IOException {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String pathInfo = StringUtils.stripStart(req.getPathInfo(), "/");
String service = StringUtils.substringAfterLast(pathInfo, "/"); String service = StringUtils.substringAfterLast(pathInfo, "/");
String repoInfo = StringUtils.substringBeforeLast(pathInfo, "/"); String repoInfo = StringUtils.substringBeforeLast(pathInfo, "/");
@ -99,10 +103,7 @@ public class GitServlet extends HttpServlet {
} }
} }
@Override protected void processRefs(HttpServletRequest req, HttpServletResponse resp, String pathInfo) throws ServletException, IOException {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String pathInfo = StringUtils.stripStart(req.getPathInfo(), "/");
if (!pathInfo.endsWith(INFO_REFS)) { if (!pathInfo.endsWith(INFO_REFS)) {
String message = "Invalid refs request url: " + req.getRequestURL(); String message = "Invalid refs request url: " + req.getRequestURL();
logger.error("Error serving git request: " + message); logger.error("Error serving git request: " + message);
@ -141,4 +142,31 @@ 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() {
}
} }

View File

@ -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/*");
}
}

View File

@ -1,11 +1,15 @@
package com.pmease.gitop.core.manager; package com.pmease.gitop.core.manager;
import java.util.Collection; import java.util.Collection;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
import com.pmease.commons.hibernate.dao.GenericDao; import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.gitop.core.manager.impl.DefaultProjectManager; import com.pmease.gitop.core.manager.impl.DefaultProjectManager;
import com.pmease.gitop.core.model.Project; 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.storage.ProjectStorage;
@ImplementedBy(DefaultProjectManager.class) @ImplementedBy(DefaultProjectManager.class)
@ -13,7 +17,11 @@ public interface ProjectManager extends GenericDao<Project> {
ProjectStorage locateStorage(Project project); 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<String> getReservedNames();
Collection<Project> findPublic(); Collection<Project> findPublic();
} }

View File

@ -1,5 +1,9 @@
package com.pmease.gitop.core.manager; package com.pmease.gitop.core.manager;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
import com.pmease.commons.hibernate.dao.GenericDao; import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.commons.util.namedentity.EntityLoader; import com.pmease.commons.util.namedentity.EntityLoader;
@ -24,7 +28,9 @@ public interface UserManager extends GenericDao<User> {
* @return * @return
* matching user, or <tt>null</tt> if not found * matching user, or <tt>null</tt> if not found
*/ */
User find(String userName); @Nullable User find(String userName);
Set<String> getReservedNames();
EntityLoader asEntityLoader(); EntityLoader asEntityLoader();
} }

View File

@ -2,6 +2,8 @@ package com.pmease.gitop.core.manager.impl;
import java.io.File; import java.io.File;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -11,24 +13,31 @@ import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.Restrictions;
import com.pmease.commons.git.Git; import com.pmease.commons.git.Git;
import com.pmease.commons.hibernate.Sessional;
import com.pmease.commons.hibernate.Transactional; import com.pmease.commons.hibernate.Transactional;
import com.pmease.commons.hibernate.dao.AbstractGenericDao; import com.pmease.commons.hibernate.dao.AbstractGenericDao;
import com.pmease.commons.hibernate.dao.GeneralDao; 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.ConfigManager;
import com.pmease.gitop.core.manager.ProjectManager; import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.model.Project; 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.storage.ProjectStorage;
import com.pmease.gitop.core.validation.ProjectNameReservation;
@Singleton @Singleton
public class DefaultProjectManager extends AbstractGenericDao<Project> implements ProjectManager { public class DefaultProjectManager extends AbstractGenericDao<Project> implements ProjectManager {
private ConfigManager configManager; private final ConfigManager configManager;
private final Set<ProjectNameReservation> nameReservations;
@Inject @Inject
public DefaultProjectManager(GeneralDao generalDao, ConfigManager configManager) { public DefaultProjectManager(GeneralDao generalDao, ConfigManager configManager, Set<ProjectNameReservation> nameReservations) {
super(generalDao); super(generalDao);
this.configManager = configManager; this.configManager = configManager;
this.nameReservations = nameReservations;
} }
@Transactional @Transactional
@ -40,8 +49,15 @@ public class DefaultProjectManager extends AbstractGenericDao<Project> implement
ProjectStorage storage = locateStorage(entity); ProjectStorage storage = locateStorage(entity);
storage.clean(); 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 { } else {
File codeDir = locateStorage(entity).ofCode();
if (!codeDir.exists()) {
FileUtils.createDir(codeDir);
new Git(codeDir).init().bare(true).call();
}
super.save(entity); super.save(entity);
} }
} }
@ -64,6 +80,7 @@ public class DefaultProjectManager extends AbstractGenericDao<Project> implement
return query(new Criterion[]{Restrictions.eq("publiclyAccessible", true)}); return query(new Criterion[]{Restrictions.eq("publiclyAccessible", true)});
} }
@Sessional
@Override @Override
public Project find(String ownerName, String projectName) { public Project find(String ownerName, String projectName) {
Criteria criteria = createCriteria(); Criteria criteria = createCriteria();
@ -75,4 +92,19 @@ public class DefaultProjectManager extends AbstractGenericDao<Project> implement
return (Project) criteria.uniqueResult(); return (Project) criteria.uniqueResult();
} }
@Override
public Set<String> getReservedNames() {
Set<String> reservedNames = new HashSet<String>();
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));
}
} }

View File

@ -1,5 +1,8 @@
package com.pmease.gitop.core.manager.impl; package com.pmease.gitop.core.manager.impl;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; 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.commons.util.namedentity.NamedEntity;
import com.pmease.gitop.core.manager.UserManager; import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.core.model.User; import com.pmease.gitop.core.model.User;
import com.pmease.gitop.core.validation.UserNameReservation;
@Singleton @Singleton
public class DefaultUserManager extends AbstractGenericDao<User> implements UserManager { public class DefaultUserManager extends AbstractGenericDao<User> implements UserManager {
private volatile Long rootUserId; private volatile Long rootUserId;
private final Set<UserNameReservation> nameReservations;
@Inject @Inject
public DefaultUserManager(GeneralDao generalDao) { public DefaultUserManager(GeneralDao generalDao, Set<UserNameReservation> nameReservations) {
super(generalDao); super(generalDao);
this.nameReservations = nameReservations;
} }
@Sessional @Sessional
@ -98,4 +106,13 @@ public class DefaultUserManager extends AbstractGenericDao<User> implements User
}; };
} }
@Override
public Set<String> getReservedNames() {
Set<String> reservedNames = new HashSet<String>();
for (UserNameReservation each: nameReservations)
reservedNames.addAll(each.getReserved());
return reservedNames;
}
} }

View File

@ -135,7 +135,7 @@ public class Project extends AbstractEntity implements UserBelonging {
public Collection<User> findAuthorizedUsers(GeneralOperation operation) { public Collection<User> findAuthorizedUsers(GeneralOperation operation) {
Set<User> authorizedUsers = new HashSet<User>(); Set<User> authorizedUsers = new HashSet<User>();
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))) if (user.asSubject().isPermitted(new ObjectPermission(this, operation)))
authorizedUsers.add(user); authorizedUsers.add(user);
} }

View File

@ -23,17 +23,8 @@ import com.pmease.gitop.core.permission.ObjectPermission;
import com.pmease.gitop.core.permission.object.ProtectedObject; import com.pmease.gitop.core.permission.object.ProtectedObject;
import com.pmease.gitop.core.permission.object.UserBelonging; import com.pmease.gitop.core.permission.object.UserBelonging;
import com.pmease.gitop.core.permission.operation.GeneralOperation; import com.pmease.gitop.core.permission.operation.GeneralOperation;
import com.pmease.gitop.core.validation.UserName;
/**
* This class represents either a project or an user in the system.
* <p>
* 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") @SuppressWarnings("serial")
@Entity @Entity
@Editable @Editable
@ -49,10 +40,8 @@ public class User extends AbstractUser implements ProtectedObject {
@Column(nullable=false) @Column(nullable=false)
private String email; private String email;
@Column
private String displayName; private String displayName;
@Column
private String avatarUrl; private String avatarUrl;
private boolean admin; private boolean admin;
@ -76,7 +65,7 @@ public class User extends AbstractUser implements ProtectedObject {
private Collection<VoteInvitation> voteVitations = new ArrayList<VoteInvitation>(); private Collection<VoteInvitation> voteVitations = new ArrayList<VoteInvitation>();
@Editable(order=100) @Editable(order=100)
@NotEmpty @UserName
@Override @Override
public String getName() { public String getName() {
return super.getName(); return super.getName();
@ -217,13 +206,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 @Override
public boolean implies(Permission permission) { public boolean implies(Permission permission) {
// Administrator can do anything // Administrator can do anything
@ -242,7 +224,7 @@ public class User extends AbstractUser implements ProtectedObject {
return true; 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()); ObjectPermission projectPermission = new ObjectPermission(each, each.getDefaultAuthorizedOperation());
if (projectPermission.implies(objectPermission)) if (projectPermission.implies(objectPermission))
return true; return true;

View File

@ -30,7 +30,7 @@ public class UserRealm extends AbstractRealm {
if (userId != 0L) { if (userId != 0L) {
return userManager.load(userId); return userManager.load(userId);
} else { } else {
return User.anonymous(); return User.ANONYMOUS;
} }
} }

View File

@ -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<? extends Payload>[] payload() default {};
}

View File

@ -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<String> getReserved();
}

View File

@ -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<ProjectName, String> {
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);
}
}

View File

@ -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<? extends Payload>[] payload() default {};
}

View File

@ -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<String> getReserved();
}

View File

@ -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<UserName, String> {
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);
}
}

View File

@ -113,6 +113,11 @@
<artifactId>commons.jersey</artifactId> <artifactId>commons.jersey</artifactId>
<version>1.0.30</version> <version>1.0.30</version>
</dependency> </dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>gitop.rest</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>
<repository> <repository>

View File

@ -10,12 +10,12 @@ import com.pmease.commons.jetty.ServerConfigurator;
import com.pmease.gitop.core.setting.ServerConfig; import com.pmease.gitop.core.setting.ServerConfig;
import com.pmease.gitop.core.setting.SslConfig; import com.pmease.gitop.core.setting.SslConfig;
public class GitopServerConfigurator implements ServerConfigurator { public class ProductConfigurator implements ServerConfigurator {
private ServerConfig serverConfig; private ServerConfig serverConfig;
@Inject @Inject
public GitopServerConfigurator(ServerConfig serverConfig) { public ProductConfigurator(ServerConfig serverConfig) {
this.serverConfig = serverConfig; this.serverConfig = serverConfig;
} }

View File

@ -6,7 +6,7 @@ import java.util.Properties;
import com.google.inject.name.Names; import com.google.inject.name.Names;
import com.pmease.commons.bootstrap.Bootstrap; import com.pmease.commons.bootstrap.Bootstrap;
import com.pmease.commons.jetty.ServerConfigurator; 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.AbstractPluginModule;
import com.pmease.commons.loader.AppName; import com.pmease.commons.loader.AppName;
import com.pmease.commons.util.FileUtils; import com.pmease.commons.util.FileUtils;
@ -30,8 +30,9 @@ public class ProductModule extends AbstractPluginModule {
bind(ServerConfig.class).to(DefaultServerConfig.class); bind(ServerConfig.class).to(DefaultServerConfig.class);
contribute(ServerConfigurator.class, GitopServerConfigurator.class); contribute(ServerConfigurator.class, ProductConfigurator.class);
contribute(ServletContextConfigurator.class, GitopServletContextConfigurator.class); contribute(ServletConfigurator.class, ProductServletConfigurator.class);
} }
} }

View File

@ -1,7 +1,5 @@
package com.pmease.gitop.product; package com.pmease.gitop.product;
import java.io.File;
import javax.inject.Inject; import javax.inject.Inject;
import org.eclipse.jetty.servlet.ServletContextHandler; 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.bootstrap.Bootstrap;
import com.pmease.commons.jetty.FileAssetServlet; 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; import com.pmease.gitop.core.setting.ServerConfig;
public class GitopServletContextConfigurator implements ServletContextConfigurator { public class ProductServletConfigurator implements ServletConfigurator {
private final ServerConfig serverConfig; private final ServerConfig serverConfig;
@Inject @Inject
public GitopServletContextConfigurator(ServerConfig serverConfig) { public ProductServletConfigurator(ServerConfig serverConfig) {
this.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 * Configure a servlet to serve contents under site folder. Site folder can be used
* to hold site specific web assets. * to hold site specific web assets.
*/ */
File siteDir = new File(Bootstrap.installDir, "site"); ServletHolder servletHolder = new ServletHolder(new FileAssetServlet(Bootstrap.getSiteDir()));
ServletHolder servletHolder = new ServletHolder(new FileAssetServlet(siteDir));
context.addServlet(servletHolder, "/site/*"); context.addServlet(servletHolder, "/site/*");
context.addServlet(servletHolder, "/robots.txt"); context.addServlet(servletHolder, "/robots.txt");
} }

57
gitop.rest/pom.xml Normal file
View File

@ -0,0 +1,57 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>gitop.rest</artifactId>
<version>1.0.0</version>
<parent>
<groupId>com.pmease</groupId>
<artifactId>parent.general</artifactId>
<version>1.0.28</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>com.pmease</groupId>
<artifactId>plugin.maven</artifactId>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>gitop.core</artifactId>
<version>1.0.30</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>pmeaseRepo</id>
<name>PMEase Repository</name>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
<url>http://artifact.pmease.com/</url>
</repository>
</repositories>
<properties>
<moduleClass>com.pmease.gitop.rest.RestModule</moduleClass>
</properties>
</project>

View File

@ -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");
}
});
}
}

View File

@ -35,11 +35,6 @@
<artifactId>commons.wicket</artifactId> <artifactId>commons.wicket</artifactId>
<version>1.0.29</version> <version>1.0.29</version>
</dependency> </dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>commons.jersey</artifactId>
<version>1.0.30</version>
</dependency>
<!-- WICKET --> <!-- WICKET -->
@ -83,6 +78,11 @@
<artifactId>dropwizard-jackson</artifactId> <artifactId>dropwizard-jackson</artifactId>
<version>0.7.0-SNAPSHOT</version> <version>0.7.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>commons.jetty</artifactId>
<version>1.0.29</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>
@ -113,24 +113,6 @@
<enabled>true</enabled> <enabled>true</enabled>
</snapshots> </snapshots>
</repository> </repository>
<repository>
<id>nexus-owsi-core</id>
<name>Nexus OWSI Core</name>
<url>https://projects.openwide.fr/services/nexus/content/repositories/owsi-core</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>nexus-owsi-core-snapshots</id>
<name>Nexus OWSI Core Snapshots</name>
<url>https://projects.openwide.fr/services/nexus/content/repositories/owsi-core-snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories> </repositories>
<properties> <properties>

View File

@ -2,17 +2,23 @@ package com.pmease.gitop.web;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.Application; import org.apache.wicket.Application;
import org.apache.wicket.Page; import org.apache.wicket.Page;
import org.apache.wicket.Session; import org.apache.wicket.Session;
import org.apache.wicket.bean.validation.BeanValidationConfiguration; 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.Request;
import org.apache.wicket.request.Response; import org.apache.wicket.request.Response;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.resource.caching.FilenameWithVersionResourceCachingStrategy; import org.apache.wicket.request.resource.caching.FilenameWithVersionResourceCachingStrategy;
import org.apache.wicket.request.resource.caching.version.LastModifiedResourceVersion; import org.apache.wicket.request.resource.caching.version.LastModifiedResourceVersion;
import org.apache.wicket.util.time.Duration; import org.apache.wicket.util.time.Duration;
@ -21,6 +27,9 @@ import org.apache.wicket.util.time.Time;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.pmease.commons.wicket.AbstractWicketConfig; 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.assets.AssetLocator;
import com.pmease.gitop.web.common.component.avatar.AvatarImageResource; import com.pmease.gitop.web.common.component.avatar.AvatarImageResource;
import com.pmease.gitop.web.common.component.avatar.AvatarImageResourceReference; import com.pmease.gitop.web.common.component.avatar.AvatarImageResourceReference;
@ -32,6 +41,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.account.setting.repos.AccountReposPage;
import com.pmease.gitop.web.page.home.HomePage; import com.pmease.gitop.web.page.home.HomePage;
import com.pmease.gitop.web.page.init.ServerInitPage; 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.LoginPage;
import com.pmease.gitop.web.shiro.LogoutPage; import com.pmease.gitop.web.shiro.LogoutPage;
import com.pmease.gitop.web.shiro.ShiroWicketPlugin; import com.pmease.gitop.web.shiro.ShiroWicketPlugin;
@ -119,8 +129,37 @@ public class GitopWebApp extends AbstractWicketConfig {
// account related pages // account related pages
// -------------------------------------------------------- // --------------------------------------------------------
// project dashboard
mount(new MountedMapper("/${user}/${project}", ProjectHomePage.class) {
@Override
protected boolean urlStartsWith(Url url, String... segments) {
List<String> 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 // account dashboard
mountPage("account/${user}", AccountHomePage.class); mount(new MountedMapper("/${user}", AccountHomePage.class) {
@Override
protected boolean urlStartsWith(Url url, String... segments) {
List<String> 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 // account settings
mountPage("settings/profile", AccountProfilePage.class); mountPage("settings/profile", AccountProfilePage.class);
@ -128,11 +167,23 @@ public class GitopWebApp extends AbstractWicketConfig {
mountPage("settings/permission", AccountPermissionPage.class); mountPage("settings/permission", AccountPermissionPage.class);
mountPage("settings/repos", AccountReposPage.class); mountPage("settings/repos", AccountReposPage.class);
mountPage("/test", TestPage.class);
// repository pages // repository pages
// -------------------------------------------------------- // --------------------------------------------------------
} }
private List<String> normalizeUrlSegments(List<String> segments) {
List<String> normalized = new ArrayList<String>();
for (String each: segments) {
each = StringUtils.remove(each, '/');
if (each.length() != 0)
normalized.add(each);
}
return normalized;
}
private void mountResources() { private void mountResources() {
getSharedResources().add(AvatarImageResourceReference.AVATAR_RESOURCE, new AvatarImageResource()); getSharedResources().add(AvatarImageResourceReference.AVATAR_RESOURCE, new AvatarImageResource());
mountResource("avatars/${type}/${id}", new AvatarImageResourceReference()); mountResource("avatars/${type}/${id}", new AvatarImageResourceReference());
@ -148,4 +199,8 @@ public class GitopWebApp extends AbstractWicketConfig {
public boolean isPublicSignupEnabled() { public boolean isPublicSignupEnabled() {
return true; return true;
} }
public Iterable<IRequestMapper> getRequestMappers() {
return getRootRequestMapperAsCompound();
}
} }

View File

@ -0,0 +1,48 @@
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.editable.EditableUtils;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.core.model.Project;
import com.pmease.gitop.web.page.BasePage;
@SuppressWarnings("serial")
public class TestPage extends BasePage {
@Override
protected void onInitialize() {
super.onInitialize();
final EditContext editContext = EditableUtils.getContext(new Project());
Form<?> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
super.onSubmit();
editContext.validate();
if (!editContext.hasValidationError(true)) {
Project project = (Project) editContext.getBean();
project.setOwner(Gitop.getInstance(UserManager.class).getRootUser());
Gitop.getInstance(ProjectManager.class).save(project);
}
}
};
form.add((Component)editContext.renderForEdit("editor"));
add(form);
}
@Override
protected String getPageTitle() {
return "Test page used by Robin";
}
}

View File

@ -1,20 +1,14 @@
package com.pmease.gitop.web; package com.pmease.gitop.web;
import javax.inject.Singleton; 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.codahale.dropwizard.jackson.Jackson; import com.codahale.dropwizard.jackson.Jackson;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Provides; import com.google.inject.Provides;
import com.pmease.commons.jetty.ClasspathAssetServlet; import com.pmease.commons.jetty.ServletConfigurator;
import com.pmease.commons.jetty.ServletContextConfigurator;
import com.pmease.commons.loader.AbstractPluginModule; import com.pmease.commons.loader.AbstractPluginModule;
import com.pmease.commons.wicket.AbstractWicketConfig; import com.pmease.commons.wicket.AbstractWicketConfig;
import com.pmease.gitop.web.assets.AssetLocator; import com.pmease.gitop.core.validation.UserNameReservation;
import com.pmease.gitop.web.resource.RestResourceModule; import com.pmease.gitop.web.resource.RestResourceModule;
/** /**
@ -31,19 +25,8 @@ public class WebModule extends AbstractPluginModule {
bind(AbstractWicketConfig.class).to(GitopWebApp.class); bind(AbstractWicketConfig.class).to(GitopWebApp.class);
bind(SitePaths.class).in(Singleton.class); bind(SitePaths.class).in(Singleton.class);
contribute(ServletContextConfigurator.class, new ServletContextConfigurator() { contribute(ServletConfigurator.class, WebServletConfigurator.class);
contribute(UserNameReservation.class, WebUserNameReservation.class);
@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");
}
});
install(new RestResourceModule()); install(new RestResourceModule());
} }

View File

@ -0,0 +1,44 @@
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;
@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");
}
}

View File

@ -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<String> getReserved() {
Set<String> reserved = new HashSet<String>();
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;
}
}

View File

@ -1,5 +1,7 @@
<html xmlns:wicket> <html xmlns:wicket>
<wicket:extend> <wicket:extend>
<h1>Welcome, Account home</h1> <h1>Welcome, Account home</h1>
<div wicket:id="accountName"></div>
<a wicket:id="link">link</a>
</wicket:extend> </wicket:extend>
</html> </html>

View File

@ -1,16 +1,79 @@
package com.pmease.gitop.web.page.account; package com.pmease.gitop.web.page.account;
import org.apache.shiro.authz.annotation.RequiresAuthentication; 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; import com.pmease.gitop.web.page.AbstractLayoutPage;
@SuppressWarnings("serial") @SuppressWarnings("serial")
@RequiresAuthentication @RequiresAuthentication
public class AccountHomePage extends AbstractLayoutPage { public class AccountHomePage extends AbstractLayoutPage {
private final IModel<User> 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<User>() {
@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<Void>("link") {
@Override
public void onClick() {
}
});
}
@Override @Override
protected String getPageTitle() { protected String getPageTitle() {
return "Gitop"; 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;
}
} }

View File

@ -31,5 +31,7 @@
<a wicket:id="vex" class="btn btn-danger">Confirmation</a> <a wicket:id="vex" class="btn btn-danger">Confirmation</a>
</div> </div>
<a wicket:id="accountLink">account</a>
<a wicket:id="projectLink">project</a>
</wicket:extend> </wicket:extend>
</html> </html>

View File

@ -1,13 +1,14 @@
package com.pmease.gitop.web.page.home; package com.pmease.gitop.web.page.home;
import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import com.pmease.commons.wicket.behavior.confirm.ConfirmBehavior; import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.web.common.component.fileupload.FileUploadResourceBehavior; import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.web.common.component.messenger.MessengerBehavior; import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.web.common.component.vex.VexBehavior; import com.pmease.gitop.web.common.component.fileupload.FileUploadBar;
import com.pmease.gitop.web.page.AbstractLayoutPage; 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 { public class HomePage extends AbstractLayoutPage {
@ -18,23 +19,13 @@ public class HomePage extends AbstractLayoutPage {
return "Gitop - Home"; return "Gitop - Home";
} }
@SuppressWarnings("serial")
@Override @Override
protected void onInitialize() { protected void onInitialize() {
super.onInitialize(); super.onInitialize();
add(new MessengerBehavior()); add(new FileUploadBar("upload"));
add(new VexBehavior());
add(new FileUploadResourceBehavior());
// add(new FileUploadBar("upload"));
add(new AjaxLink<Void>("vex") { 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))));
@Override
public void onClick(AjaxRequestTarget target) {
System.out.println("xxx");
}
}.add(new ConfirmBehavior("Are you sure?")));
} }
} }

View File

@ -0,0 +1,9 @@
<html xmlns:wicket>
<wicket:extend>
<h1>Welcome, Project Home</h1>
<div wicket:id="accountName"></div>
<div wicket:id="projectName"></div>
<a wicket:id="link">link</a>
</wicket:extend>
</html>

View File

@ -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<Project> 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<Project>() {
@Override
protected Project load() {
return Gitop.getInstance(ProjectManager.class).load(projectId);
}
};
add(new Link<Void>("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;
}
}

View File

@ -1,9 +1,10 @@
package com.pmease.gitop.web.page.test; package com.pmease.gitop.web.page.test;
import org.apache.wicket.Component;
import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.Form;
import com.pmease.commons.editable.EditContext; 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.Gitop;
import com.pmease.gitop.core.manager.ProjectManager; import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.manager.UserManager; import com.pmease.gitop.core.manager.UserManager;
@ -17,7 +18,7 @@ public class TestPage extends BasePage {
protected void onInitialize() { protected void onInitialize() {
super.onInitialize(); super.onInitialize();
final EditContext editContext = EditHelper.getContext(new Project()); final EditContext editContext = EditableUtils.getContext(new Project());
Form<?> form = new Form<Void>("form") { Form<?> form = new Form<Void>("form") {
@ -34,7 +35,7 @@ public class TestPage extends BasePage {
}; };
form.add(EditHelper.renderForEdit(editContext, "editor")); form.add((Component) editContext.renderForEdit("editor"));
add(form); add(form);
} }