/******************************************************************************* * Copyright 2011 Alex 'Ript' Malyshev <alexript@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package net.autosauler.ballance.server.mongodb; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.UnknownHostException; import java.util.Date; import java.util.HashMap; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import net.autosauler.ballance.server.model.AbstractCatalog; import net.autosauler.ballance.server.model.AbstractDocument; import net.autosauler.ballance.server.model.Currency; import net.autosauler.ballance.server.model.GlobalSettings; import net.autosauler.ballance.server.model.Scripts; import net.autosauler.ballance.server.model.Structures; import net.autosauler.ballance.server.model.UserList; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.allen_sauer.gwt.log.client.Log; import com.mongodb.DB; import com.mongodb.Mongo; import com.mongodb.MongoException; /** * The Class Database. */ public class Database { // TODO: all connect values must be configurable /** The Constant host. */ private static final String host = "127.0.0.1"; /** The Constant port. */ private static final int port = 27017; /** The Constant database. */ private static final String database = "blncatslrnt"; /** The Constant user. */ private static final String user = "user"; /** The Constant password. */ private static final String password = "user"; /** The Constant adminuser. */ private static final String adminuser = "root"; /** The Constant adminpassword. */ private static final String adminpassword = "root"; /** The mongo. */ private static Mongo mongo = null; /** The mongodatabase. */ private static DB mongodatabase = null; /** The lockcounter. */ private static Integer lockcounter = 0; /** The releaser. */ private static Thread releaser = null; /** The retaintimeoutmin. */ private static int retaintimeoutmin = 5; /** The settings. */ private static GlobalSettings settings = null; /** * Close connection. */ public static synchronized void close() { mongodatabase = null; if (mongo != null) { mongo.close(); mongo = null; } if (releaser != null) { releaser = null; } lockcounter = 0; if (settings != null) { settings.save(); } } public static void dumpdatabase(String domain, String username, String filename) { // TODO: return boolean, write to stream // TODO: add xml scheme // TODO: generate filename StringBuilder sb = new StringBuilder(); sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); sb.append("<dump date=\"" + new Date().getTime() + "\">\n"); GlobalSettings settings = new GlobalSettings(domain); sb.append(settings.dump()); sb.append(UserList.dump(domain)); sb.append("<catalogs>\n"); AbstractCatalog cat = new AbstractCatalog("paymethod", domain, username); sb.append(cat.dump()); cat = new AbstractCatalog("partners", domain, username); sb.append(cat.dump()); cat = new AbstractCatalog("tarifs", domain, username); sb.append(cat.dump()); sb.append("</catalogs>\n<documents>\n"); AbstractDocument doc = new AbstractDocument("inpay", domain, username); sb.append(doc.dump()); doc = new AbstractDocument("ingoods", domain, username); sb.append(doc.dump()); sb.append("</documents>\n"); sb.append(Scripts.dump(domain)); sb.append(Structures.dump(domain)); sb.append("</dump>\n"); String s = sb.toString(); BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(filename)); out.write(s); out.flush(); out.close(); } catch (IOException e) { if (out != null) { try { out.flush(); out.close(); } catch (IOException e1) { Log.error(e1.getMessage()); } } Log.error(e.getMessage()); } } /** * Gets the database. * * @return the dB */ public static synchronized DB get(String domain) { if (mongodatabase == null) { try { initConnection(domain); } catch (UnknownHostException e) { close(); Log.error(e.getMessage()); } catch (MongoException e) { close(); Log.error(e.getMessage()); } catch (InterruptedException e) { close(); Log.error(e.getMessage()); } } return mongodatabase; } /** * Gets the all settings. * * @return the all settings */ public static HashMap<String, String> getAllSettings(String domain) { if (settings == null) { loadSettings(domain); } return settings.getAll(); } /** * Gets the settings. * * @return the settings */ public static GlobalSettings getSettings() { return settings; } /** * Inits the connection. * * @throws UnknownHostException * the unknown host exception * @throws MongoException * the mongo exception * @throws InterruptedException * the interrupted exception */ private static synchronized void initConnection(String domain) throws UnknownHostException, MongoException, InterruptedException { try { if (mongo == null) { mongo = new Mongo(host, port); } } catch (com.mongodb.MongoInternalException e) { close(); throw (e); } DB db = mongo.getDB("admin"); boolean auth = db.authenticate(adminuser, adminpassword.toCharArray()); if (auth) { List<String> databases = mongo.getDatabaseNames(); db = mongo.getDB(database); if (!databases.contains(database)) { db.addUser(user, password.toCharArray()); } auth = db.authenticate(user, password.toCharArray()); if (auth) { mongodatabase = db; retain(); // check settings and create new collection if not exists GlobalSettings.createDefaultRecords(db); // check users and if none - create admin UserList.createDefaultRecords(db); // check currency values. If none - load today values from cbr Currency.createDefaultRecords(db); release(); } else { close(); } } else { close(); } loadSettings(domain); } private static void loadSettings(String domain) { if ((domain == null) || domain.isEmpty()) { domain = "127.0.0.1"; } if (mongodatabase != null) { settings = new GlobalSettings(domain); retaintimeoutmin = settings.get("database.autoclose.timeout.min", retaintimeoutmin); settings.save(); } else { settings = new GlobalSettings(false, domain); } } /** * Recreate database (drop and close connection). * * @return true, if successful */ public static synchronized boolean recreateDb() { if (mongodatabase == null) { return false; } try { Database.retain(); mongodatabase.dropDatabase(); close(); } catch (MongoException e) { Log.error(e.getMessage()); return false; } return true; } /** * Retain database lock counter. */ public static synchronized void release() { lockcounter--; if ((lockcounter == 0) && (mongodatabase != null)) { mongodatabase.requestDone(); } if (lockcounter < 0) { lockcounter = 0; } } /** * Restoredatabase. * * @param domain * the domain * @param username * the username * @param filename * the filename */ public static void restoredatabase(String domain, String username, String filename) { // TODO: complete File dump = new File(filename); DocumentBuilder builder; try { builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse(dump); NodeList rootnodes = doc.getElementsByTagName("dump"); for (int i = 0; i < rootnodes.getLength(); i++) { Element rootelement = (Element) rootnodes.item(i); NodeList sections = rootelement.getChildNodes(); for (int c = 0; c < sections.getLength(); c++) { Node v = sections.item(c); if (v.getNodeType() == Node.ELEMENT_NODE) { Element val = (Element) v; if (val.getNodeName().equals("settings")) { GlobalSettings s = new GlobalSettings(domain); s.restore(val); } else if (val.getNodeName().equals("scripts")) { Scripts s = new Scripts(domain, username); s.restore(val); } else if (val.getNodeName().equals("structures")) { Structures s = new Structures(domain); s.restore(val); } else if (val.getNodeName().equals("users")) { UserList.restore(domain, val); } else if (val.getNodeName().equals("catalogs")) { NodeList catnodes = val.getElementsByTagName("cat"); for (int j = 0; j < catnodes.getLength(); j++) { Element cat = (Element) catnodes.item(j); String catname = cat.getAttribute("name"); AbstractCatalog ac = new AbstractCatalog( catname, domain, username); ac.restore(cat); } } else if (val.getNodeName().equals("documents")) { NodeList docnodes = val.getElementsByTagName("doc"); for (int j = 0; j < docnodes.getLength(); j++) { Element document = (Element) docnodes.item(j); String docname = document.getAttribute("name"); if (docname.equals("inpay")) { AbstractDocument p = new AbstractDocument( "inpay", domain, username); p.restore(document); } else if (docname.equals("ingoods")) { AbstractDocument g = new AbstractDocument( "ingoods", domain, username); g.restore(document); } } } } } } } catch (ParserConfigurationException e) { Log.error(e.getMessage()); } catch (SAXException e) { Log.error(e.getMessage()); } catch (IOException e) { Log.error(e.getMessage()); } } /** * Retain database lock counter. */ public static synchronized void retain() { lockcounter++; if ((lockcounter == 1) && (mongodatabase != null)) { mongodatabase.requestStart(); } startReleaser(); } /** * Sets the settings. * * @param newvalues * the newvalues */ public static void setSettings(HashMap<String, String> newvalues) { settings.set(newvalues); } /** * Start releaser thread. */ private static void startReleaser() { if (releaser == null) { releaser = new Thread(new Runnable() { @Override public void run() { try { while (lockcounter > 0) { Thread.sleep(retaintimeoutmin * 60 * 1000); } close(); } catch (InterruptedException e) { Log.error(e.getMessage()); } } }); releaser.start(); } } /** * Instantiates a new database. */ public Database() { } }