System initialization logic.

This commit is contained in:
robin shine 2013-09-18 22:36:20 +08:00
parent c1bce23af2
commit 379fd71c9c
21 changed files with 240 additions and 328 deletions

View File

@ -1,5 +1,7 @@
package com.pmease.commons.hibernate.dao;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.List;
import org.hibernate.Criteria;
@ -13,10 +15,11 @@ import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.commons.hibernate.Transactional;
import com.pmease.commons.loader.ManagedSerializedForm;
@Singleton
@SuppressWarnings("unchecked")
public class DefaultGeneralDao implements GeneralDao {
public class DefaultGeneralDao implements GeneralDao, Serializable {
private final Provider<SessionFactory> sessionFactoryProvider;
@ -104,4 +107,8 @@ public class DefaultGeneralDao implements GeneralDao {
return (Integer) criteria.uniqueResult();
}
public Object writeReplace() throws ObjectStreamException {
return new ManagedSerializedForm(GeneralDao.class);
}
}

View File

@ -0,0 +1,20 @@
package com.pmease.commons.loader;
import java.io.ObjectStreamException;
import java.io.Serializable;
public class ManagedSerializedForm implements Serializable {
private static final long serialVersionUID = 1L;
private Class<?> managedClass;
public ManagedSerializedForm(Class<?> managedClass) {
this.managedClass = managedClass;
}
public Object readResolve() throws ObjectStreamException {
return AppLoader.getInstance(managedClass);
}
}

View File

@ -0,0 +1,72 @@
package com.pmease.commons.util.init;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.SerializationUtils;
@SuppressWarnings("serial")
public class InitStage implements Serializable, Cloneable {
private String message;
private final List<ManualConfig> manualConfigs;
public InitStage(String message, List<ManualConfig> manualConfigs) {
this.message = message;
this.manualConfigs = manualConfigs;
}
public InitStage(String message) {
this(message, new ArrayList<ManualConfig>());
}
public String getMessage() {
return message;
}
public synchronized void waitFor() {
if (!manualConfigs.isEmpty()) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
manualConfigs.clear();
}
}
@Override
public synchronized InitStage clone() {
if (!manualConfigs.isEmpty()) {
List<ManualConfig> clonedConfigs = new ArrayList<ManualConfig>();
for (ManualConfig each: manualConfigs)
clonedConfigs.add(SerializationUtils.clone(each));
final ManualConfig lastConfig = clonedConfigs.remove(clonedConfigs.size()-1);
clonedConfigs.add(new ManualConfig(lastConfig.getSetting()) {
@Override
public Skippable getSkippable() {
return lastConfig.getSkippable();
}
@Override
public void complete() {
lastConfig.complete();
synchronized (InitStage.this) {
InitStage.this.notify();
message = "Please wait...";
}
}
});
return new InitStage(message, clonedConfigs);
} else {
return new InitStage(message);
}
}
}

View File

@ -1,4 +1,4 @@
package com.pmease.gitop.core;
package com.pmease.commons.util.init;
import java.io.Serializable;

View File

@ -1,4 +1,4 @@
package com.pmease.gitop.core;
package com.pmease.commons.util.init;
public interface Skippable {
void skip();

View File

@ -1,80 +1,64 @@
package com.pmease.gitop.core;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.apache.commons.lang3.SerializationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.pmease.commons.loader.AbstractPlugin;
import com.pmease.commons.loader.AppLoader;
import com.pmease.commons.loader.AppName;
import com.pmease.gitop.core.manager.InitManager;
import com.pmease.commons.util.init.InitStage;
import com.pmease.commons.util.init.ManualConfig;
import com.pmease.gitop.core.manager.DataManager;
import com.pmease.gitop.core.setting.ServerConfig;
public class Gitop extends AbstractPlugin {
private static final Logger logger = LoggerFactory.getLogger(Gitop.class);
private final InitManager initManager;
private final DataManager dataManager;
private final ServerConfig serverConfig;
private final String appName;
private List<ManualConfig> manualConfigs;
private volatile InitStage initStage;
@Inject
public Gitop(ServerConfig serverConfig, InitManager initManager, @AppName String appName) {
this.initManager = initManager;
public Gitop(ServerConfig serverConfig, DataManager dataManager, @AppName String appName) {
this.dataManager = dataManager;
this.serverConfig = serverConfig;
this.appName = appName;
initStage = new InitStage("Server is Starting...");
}
@SuppressWarnings("serial")
@Override
public void start() {
manualConfigs = initManager.init();
if (!manualConfigs.isEmpty()) synchronized (manualConfigs) {
final ManualConfig lastConfig = manualConfigs.remove(manualConfigs.size()-1);
List<ManualConfig> manualConfigs = dataManager.init();
if (!manualConfigs.isEmpty()) {
logger.warn("Please set up the server at " + Gitop.getInstance().guessServerUrl() + ".");
initStage = new InitStage("Server Setup", manualConfigs);
manualConfigs.add(new ManualConfig(lastConfig.getSetting()) {
@Override
public Skippable getSkippable() {
return lastConfig.getSkippable();
}
@Override
public void complete() {
lastConfig.complete();
synchronized (manualConfigs) {
manualConfigs.notify();
}
}
});
logger.warn("Please point your browser to '" + guessServerUrl() + "' to set up the server.");
try {
manualConfigs.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
manualConfigs.clear();
initStage.waitFor();
}
}
@Override
public void postStart() {
initStage = null;
logger.info("Server is ready at " + guessServerUrl() + ".");
}
public String guessServerUrl() {
String hostName;
try {
@ -94,19 +78,24 @@ public class Gitop extends AbstractPlugin {
}
/**
* This method can be called from different UI threads, so we clone manual configs to
* This method can be called from different UI threads, so we clone initStage to
* make it thread-safe.
* <p>
* @return
* cloned list of manual configs
* cloned initStage, or <tt>null</tt> if system initialization is completed
*/
@SuppressWarnings("unchecked")
public List<ManualConfig> getManualConfigs() {
synchronized (manualConfigs) {
return (List<ManualConfig>) SerializationUtils.clone((Serializable) manualConfigs);
public @Nullable InitStage getInitStage() {
if (initStage != null) {
return initStage.clone();
} else {
return null;
}
}
public boolean isReady() {
return initStage == null;
}
public static Gitop getInstance() {
return AppLoader.getInstance(Gitop.class);
}

View File

@ -0,0 +1,14 @@
package com.pmease.gitop.core.manager;
import java.util.List;
import com.google.inject.ImplementedBy;
import com.pmease.commons.util.init.ManualConfig;
import com.pmease.gitop.core.manager.impl.DefaultDataManager;
@ImplementedBy(DefaultDataManager.class)
public interface DataManager {
List<ManualConfig> init();
}

View File

@ -1,14 +0,0 @@
package com.pmease.gitop.core.manager;
import java.util.List;
import com.google.inject.ImplementedBy;
import com.pmease.gitop.core.ManualConfig;
import com.pmease.gitop.core.manager.impl.DefaultInitManager;
@ImplementedBy(DefaultInitManager.class)
public interface InitManager {
List<ManualConfig> init();
}

View File

@ -1,5 +1,7 @@
package com.pmease.gitop.core.manager.impl;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@ -9,10 +11,11 @@ import javax.inject.Singleton;
import org.hibernate.criterion.Order;
import com.pmease.commons.hibernate.Transactional;
import com.pmease.gitop.core.ManualConfig;
import com.pmease.gitop.core.Skippable;
import com.pmease.commons.loader.ManagedSerializedForm;
import com.pmease.commons.util.init.ManualConfig;
import com.pmease.commons.util.init.Skippable;
import com.pmease.gitop.core.manager.ConfigManager;
import com.pmease.gitop.core.manager.InitManager;
import com.pmease.gitop.core.manager.DataManager;
import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.core.model.Config;
import com.pmease.gitop.core.model.Config.Key;
@ -21,14 +24,14 @@ import com.pmease.gitop.core.setting.MailSetting;
import com.pmease.gitop.core.setting.StorageSetting;
@Singleton
public class DefaultInitManager implements InitManager {
public class DefaultDataManager implements DataManager, Serializable {
private final UserManager userManager;
private final ConfigManager configManager;
@Inject
public DefaultInitManager(UserManager userManager, ConfigManager configManager) {
public DefaultDataManager(UserManager userManager, ConfigManager configManager) {
this.userManager = userManager;
this.configManager = configManager;
}
@ -98,5 +101,9 @@ public class DefaultInitManager implements InitManager {
return manualConfigs;
}
public Object writeReplace() throws ObjectStreamException {
return new ManagedSerializedForm(DataManager.class);
}
}

View File

@ -1,27 +0,0 @@
package com.pmease.gitop.product;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.pmease.commons.loader.AbstractPlugin;
public class Product extends AbstractPlugin {
private static final Logger logger = LoggerFactory.getLogger(Product.class);
public static final String NAME = "Gitop";
@Override
public void postStart() {
logger.info(NAME + " has been started successfully.");
}
@Override
public void start() {
}
@Override
public void stop() {
}
}

View File

@ -7,7 +7,6 @@ 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.loader.AbstractPlugin;
import com.pmease.commons.loader.AbstractPluginModule;
import com.pmease.commons.loader.AppName;
import com.pmease.commons.util.FileUtils;
@ -19,7 +18,7 @@ public class ProductModule extends AbstractPluginModule {
protected void configure() {
super.configure();
bindConstant().annotatedWith(AppName.class).to(Product.NAME);
bindConstant().annotatedWith(AppName.class).to("Gitop");
Properties hibernateProps = FileUtils.loadProperties(
new File(Bootstrap.installDir, "conf/hibernate.properties"));
@ -35,9 +34,4 @@ public class ProductModule extends AbstractPluginModule {
contribute(ServletContextConfigurator.class, GitopServletContextConfigurator.class);
}
@Override
protected Class<? extends AbstractPlugin> getPluginClass() {
return Product.class;
}
}

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title wicket:id="title"></title>
</head>
<body>
<wicket:child></wicket:child>
</body>
</html>

View File

@ -0,0 +1,36 @@
package com.pmease.gitop.web;
import org.apache.wicket.RestartResponseAtInterceptPageException;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import com.pmease.commons.wicket.asset.CommonResourceReference;
import com.pmease.gitop.core.Gitop;
@SuppressWarnings("serial")
public abstract class BasePage extends WebPage {
public BasePage() {
if (!Gitop.getInstance().isReady() && getClass() != InitPage.class)
throw new RestartResponseAtInterceptPageException(InitPage.class);
}
@Override
protected void onInitialize() {
super.onInitialize();
add(new Label("title", getTitle()));
}
protected abstract String getTitle();
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptHeaderItem.forReference(new CommonResourceReference()));
}
}

View File

@ -1,80 +0,0 @@
package com.pmease.gitop.web;
import java.io.Serializable;
import java.util.List;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
import com.pmease.commons.editable.EditContext;
import com.pmease.commons.editable.Validatable;
import com.pmease.commons.editable.annotation.Editable;
@SuppressWarnings("serial")
@Editable
public class Bean implements Serializable, Validatable {
private String name;
private boolean married;
private List<ChildBean> childs;
private ChildBean child;
private Integer age;
@Editable(description="This is something interesting.")
@NotEmpty
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Editable
public boolean isMarried() {
return married;
}
public void setMarried(boolean married) {
this.married = married;
}
@Editable
@Size(min=5)
public List<ChildBean> getChilds() {
return childs;
}
public void setChilds(List<ChildBean> childs) {
this.childs = childs;
}
@Editable
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Editable
public ChildBean getChild() {
return child;
}
public void setChild(ChildBean child) {
this.child = child;
}
@Override
public void validate(EditContext editContext) {
editContext.error("tananade");
}
}

View File

@ -1,47 +0,0 @@
package com.pmease.gitop.web;
import java.io.Serializable;
import org.hibernate.validator.constraints.NotEmpty;
import com.pmease.commons.editable.EditContext;
import com.pmease.commons.editable.Validatable;
import com.pmease.commons.editable.annotation.Editable;
@SuppressWarnings("serial")
@Editable
public abstract class ChildBean implements Serializable, Validatable {
private String childName;
private Boolean childMarried;
@Editable
@NotEmpty
public String getChildName() {
return childName;
}
public void setChildName(String childName) {
this.childName = childName;
}
@Editable
public Boolean isChildMarried() {
return childMarried;
}
public void setChildMarried(Boolean childMarried) {
this.childMarried = childMarried;
}
@Override
public void validate(EditContext editContext) {
if (!editContext.hasError("childName", true)) {
if (childName.startsWith("child") && childMarried) {
editContext.error("child can not marry.");
editContext.getChildContext("childMarried").error("child can not marry.");
}
}
}
}

View File

@ -1,13 +1,3 @@
<!DOCTYPE html>
<html>
<head>
<title>Product Home Page</title>
</head>
<body>
<div wicket:id="feedback"></div>
<form wicket:id="form" style="margin:8px;">
<div wicket:id="editor"></div>
<input type="submit" value="save" class="btn btn-primary"></input>
</form>
</body>
</html>
<wicket:extend>
Welcome Home!
</wicket:extend>

View File

@ -1,61 +1,16 @@
package com.pmease.gitop.web;
import java.util.ArrayList;
import org.apache.wicket.Component;
import org.apache.wicket.feedback.ContainerFeedbackMessageFilter;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import com.pmease.commons.editable.EditContext;
import com.pmease.commons.editable.ValidationError;
import com.pmease.commons.wicket.asset.CommonResourceReference;
import com.pmease.commons.wicket.editable.EditHelper;
@SuppressWarnings("serial")
public class HomePage extends WebPage {
public class HomePage extends BasePage {
private static Bean bean = new Bean();
static {
bean.setChilds(new ArrayList<ChildBean>());
bean.getChilds().add(new TimBean());
bean.getChilds().add(new TinaBean());
}
@Override
protected void onInitialize() {
super.onInitialize();
final EditContext editContext = EditHelper.getContext(bean);
Form<?> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
editContext.validate();
for (ValidationError each: editContext.getValidationErrors(true)) {
System.out.println(each);
}
}
};
add(new FeedbackPanel("feedback", new ContainerFeedbackMessageFilter(form)));
form.add((Component)editContext.renderForView("editor"));
add(form);
}
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptHeaderItem.forReference(new CommonResourceReference()));
protected String getTitle() {
return "Home Page";
}
}

View File

@ -0,0 +1,3 @@
<wicket:extend>
Init
</wicket:extend>

View File

@ -0,0 +1,22 @@
package com.pmease.gitop.web;
import org.apache.wicket.RestartResponseException;
import com.pmease.commons.util.init.InitStage;
import com.pmease.gitop.core.Gitop;
@SuppressWarnings("serial")
public class InitPage extends BasePage {
public InitPage() {
InitStage initStage = Gitop.getInstance().getInitStage();
if (initStage == null)
throw new RestartResponseException(HomePage.class);
}
@Override
protected String getTitle() {
return "Initialization";
}
}

View File

@ -1,19 +0,0 @@
package com.pmease.gitop.web;
import com.pmease.commons.editable.annotation.Editable;
@SuppressWarnings("serial")
@Editable
public class TimBean extends ChildBean {
private int score;
@Editable
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}

View File

@ -1,19 +0,0 @@
package com.pmease.gitop.web;
import com.pmease.commons.editable.annotation.Editable;
@SuppressWarnings("serial")
@Editable
public class TinaBean extends ChildBean {
private boolean legInjured;
@Editable
public boolean isLegInjured() {
return legInjured;
}
public void setLegInjured(boolean legInjured) {
this.legInjured = legInjured;
}
}