BootstrapBean.java 6.29 KB
package fi.codecrew.moya.beans;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ejb.Singleton;
import javax.ejb.Startup;

import fi.codecrew.moya.facade.DBModelFacade;
import fi.codecrew.moya.facade.UserFacade;
import fi.codecrew.moya.model.DBModel;
import fi.codecrew.moya.model.User;

@Singleton
@Startup
public class BootstrapBean implements BootstrapBeanLocal {

	@EJB
	UserFacade userFacade;

	public BootstrapBean() {
	}

	/**
	 * Runs a "ALTER TABLE
	 * <table>
	 * <statement>" for each of tables.
	 * 
	 * @param alterStatement
	 *            e.g. "ADD meta json"
	 * @param tables
	 *            table name strings
	 * @return1
	 */
	private static final String[] alterTables(String alterStatement, String... tables) {
		String[] strings = new String[tables.length];
		for (int i = 0; i < tables.length; i++) {
			strings[i] = "ALTER TABLE  \"" + tables[i] + "\" " + alterStatement;
		}
		return strings;
	}

	private static final List<String[]> dbUpdates = new ArrayList<String[]>();
	static {
		// {"Query1","Query2",...}
		dbUpdates.add(new String[] { "" }); // first version, no changes
		dbUpdates.add(new String[] { "ALTER TABLE tournaments ADD COLUMN game integer NOT NULL REFERENCES tournament_games(id)" });
		dbUpdates.add(new String[] { "ALTER TABLE tournaments ADD COLUMN rules integer NOT NULL REFERENCES tournament_rules(id)" });
		dbUpdates.add(new String[] { "ALTER TABLE tournaments ADD COLUMN max_participants integer NOT NULL DEFAULT 0" });
		dbUpdates.add(new String[] { "ALTER TABLE tournament_participants ADD COLUMN tournament integer NOT NULL REFERENCES tournaments(id)" });
		dbUpdates.add(new String[] { "DELETE FROM application_permissions WHERE application = 'MAP' and permission = 'RELEASE_PLACE'" });
		dbUpdates.add(new String[] { "ALTER TABLE site_page_content ADD COLUMN locale varchar(10)" });
		dbUpdates.add(new String[] { "ALTER TABLE products ALTER COLUMN vat TYPE NUMERIC(4,3)" });
		dbUpdates.add(new String[] { "ALTER TABLE actionlog_messages DROP COLUMN crew" });
		dbUpdates.add(new String[] { "delete from application_permissions where application ilike '%terminal%'" });
		dbUpdates.add(new String[] {
				"ALTER TABLE org_roles ADD ldap_role boolean not null default false",
				"ALTER TABLE org_roles ADD ldap_weight integer NOT NULL default 100"
		});
		// barcodefuckup
		dbUpdates.add(new String[] {
				"DROP TABLE card_barcode",
				"ALTER TABLE printed_cards DROP COLUMN barcode;",
				"ALTER TABLE printed_cards DROP COLUMN rfid_uid;",
				"ALTER TABLE reader_events ADD COLUMN event_users_id integer REFERENCES event_users(id) DEFAULT null;",
				"ALTER TABLE reader_events ADD COLUMN places_id integer REFERENCES places(id) DEFAULT null;",
				"ALTER TABLE reader_events ADD COLUMN products_id integer REFERENCES products(id) DEFAULT null;",
				"ALTER TABLE reader_events ADD COLUMN type text NOT NULL DEFAULT 'UNKNOWN';",
				"ALTER TABLE reader_events DROP COLUMN gamepoint;",
				"ALTER TABLE reader_events ALTER COLUMN type DROP DEFAULT;",
		});

		dbUpdates.add(new String[] {
				"delete from menu_navigation where item_id in (select id from menuitem where url in ( '/actionlog/messagelist'))",
				"delete from menuitem where url in ('/actionlog/messagelist')",
		});
		dbUpdates.add(new String[] {
				"alter table compos add hidden boolean default false not null"
		});
		dbUpdates.add(alterTables("ADD COLUMN meta json",
				"account_events",
				"actionlog_message_responses",
				"actionlog_message_tags",
				"actionlog_messages",
				"api_application_instances",
				"api_applications",
				"application_permissions",
				"approvals",
				"bill_lines",
				"bills",
				"card_code",
				"card_templates",
				"compo_entries",
				"compo_entry_files",
				"compo_entry_participations",
				"compo_votes",
				"compos",
				"discount_instances",
				"discounts",
				"event_domains",
				"event_log",
				"event_log_types",
				"event_organiser",
				"event_private_properties",
				"event_properties",
				"event_users",
				"events",
				"feedback",
				"food_wave_templates",
				"food_waves",
				"game_ids",
				"group_memberships",
				"groups",
				"inventory_events",
				"licensetargets",
				"licensecodes",
				"locations",
				"maps",
				"match_results",
				"matches",
				"menu_navigation",
				"menuitem",
				"news",
				"news_groups",
				"org_roles",
				"places",
				"poll",
				"poll_answer",
				"poll_question",
				"possible_answer",
				"printed_cards",
				"product_limitations",
				"products",
				"reader_events",
				"readers",
				"roles",
				"sales_entity",
				"salespoint",
				"site_page_content",
				"site_pages",
				"tournament_games",
				"tournament_participants",
				"tournament_rules",
				"tournament_team_members",
				"tournaments",
				"user_approvals",
				"user_images",
				"user_notes",
				"users"));
	}

	@EJB
	private DBModelFacade dbModelFacade;

	@PostConstruct
	public void bootstrap() {
		this.doDBUpdates();
	}

	private void doDBUpdates() {
		DBModel dBm = dbModelFacade.findLastRevision();
		Integer upIdx = (dbUpdates.size() - 1);
		if (dBm != null) {
			Integer revId = dBm.getRevision();

			// Check if we have unapplied updates
			if ((dbUpdates.size() - 1) > revId) {
				// Oh yes we do

				this.executeUpdates(revId, upIdx);
			} else if (upIdx < revId) {
				throw new RuntimeException("Sanity check failed! DB is newer than the codebase!");
			}
		} else {
			// DB is up to date by default! We need to mark the current version
			// down though.
			dBm = new DBModel();
			dBm.setRevision(upIdx);
			dbModelFacade.create(dBm);
		}
	}

	private void executeUpdates(Integer dbRev, Integer targetRev) {
		while (dbRev < targetRev) {
			dbRev++;

			System.out.format("attempt to upgrade db from version %d -> %d", (dbRev - 1), dbRev);

			String[] queries = dbUpdates.get(dbRev);
			for (String query : queries) {
				if (!query.isEmpty()) {
					dbModelFacade.updateModel(query);
				}
			}
			System.out.println("update ok!");

			DBModel dBm = new DBModel();
			dBm.setRevision(dbRev);
			dbModelFacade.create(dBm);
		}
	}

	public void saneDefaults() {
		User adminUser = userFacade.findByLogin("admin");
		if (adminUser == null) {
			adminUser = new User();
			adminUser.setLogin("admin");
			// adminUser.setSuperadmin(true);
			adminUser.resetPassword("admin");
			userFacade.create(adminUser);
		}
	}

}