/* * Copyright (C) 2004-2011 Centro de Computacao Cientifica e Software Livre * Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR * * This file is part of datasid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package br.ufpr.c3sl.datasid; import java.io.*; import java.util.*; import java.util.regex.*; import java.text.SimpleDateFormat; import java.text.ParseException; import java.math.BigInteger; import java.sql.Timestamp; import java.sql.SQLException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.Types; import javax.naming.InitialContext; import javax.sql.DataSource; import javax.xml.bind.*; import javax.xml.bind.util.ValidationEventCollector; import javax.xml.bind.helpers.DefaultValidationEventHandler; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.transform.stream.StreamSource; public class DataSID { // enum does not work as expected inside an axis web service // using simple constants instead private static final int LINUX = 0; private static final int WINDOWS = 1; private static final int ERROR = 0; private static final int WARNING = 1; private static final int INFO = 2; private static final int DEBUG = 3; private Properties prop; private File xml_inventory_schema; private File xml_net_usage_schema; private String linux_agent_version; private String linux_agent_update_link; private String windows_agent_version; private String windows_agent_update_link; public DataSID() throws IOException { try { this.prop = new Properties(); this.prop.load(new FileInputStream("../conf/webservice.properties")); } catch (IOException e) { System.err.println("Failed to load webservice.properties."); throw e; } this.xml_inventory_schema = new File(this.prop.getProperty("xml_inventory_schema", "../conf/collected-data.xsd")); this.xml_net_usage_schema = new File(this.prop.getProperty("xml_net_usage_schema", "../conf/net-collected-data.xsd")); this.linux_agent_version = this.prop.getProperty("linux_agent_version", "1.0.0"); this.linux_agent_update_link = this.prop.getProperty("linux_agent_update_link", "http://bisimmcdev.c3sl.ufpr.br/download/datasid-1.0.0-update.run"); this.windows_agent_version = this.prop.getProperty("windows_agent_version", "1.0.0"); this.windows_agent_update_link = this.prop.getProperty("windows_agent_update_link", "http://bisimmcdev.c3sl.ufpr.br/download/datasid-1.0.0-update.exe"); } /** * Returns the name of the log level * * @author Eduardo Luis Buratti * @param level Log level */ private static String logLevelName(int level) { if (level == ERROR) return "ERROR"; else if (level == WARNING) return "WARNING"; else if (level == INFO) return "INFO"; else if (level == DEBUG) return "DEBUG"; else return "NULL"; } /** * Write messages to the log * * @author Eduardo Luis Buratti * @param level Log level * @param msg Message */ private static void log(int level, String msg) { System.out.println(getTimestamp() + " [DataSidWS][" + logLevelName(level) + "]: " + msg); } /** * Returns a string representing the current date * * @author Eduardo Luis Buratti * @return String */ private static String getDate() { Calendar date = Calendar.getInstance(); // gets current date int year = date.get(Calendar.YEAR); int month = date.get(Calendar.MONTH); int day = date.get(Calendar.DATE); /* NOTE: Calendar.MONTH field value is 0-based. e.g: 0 is January */ month++; return year + "-" + month + "-" + day; } /** * Returns current timestamp * * @author Eduardo Luis Buratti * @return String */ private static String getTimestamp() { // gets the current time java.util.Date date = new java.util.Date(); long milisecs = date.getTime(); // generates timestamp string Timestamp timestamp = new Timestamp(milisecs); return timestamp.toString(); } /** * Return a string with current agent version. * * @author Eduardo Luis Buratti * @param OS Integer of OS Type * @return String */ public String getAgentVersion(int OS) { switch(OS){ case LINUX: return this.linux_agent_version; case WINDOWS: return this.windows_agent_version; default: return "ERROR: invalid OS"; } } /** * Return a string that contains a link to download the newest version of * agent. * * @author Eduardo Luis Buratti * @param OS Integer of OS Type * @return String */ public String getUpdateLink(int OS) { switch(OS){ case LINUX: return this.linux_agent_update_link; case WINDOWS: return this.windows_agent_update_link; default: return "ERROR: invalid OS"; } } /** * Receive an XML string which has the inventory data to be parsed and * inserted into database. Return "Success" string if insertion operation * is successful. Any other errors will throw exceptions. * * @author Eduardo Luis Buratti * @param xmlData XML string of inventory * @return String */ public String setInventory(String xmlData) { try { InitialContext cxt = new InitialContext(); DataSource ds = (DataSource) cxt.lookup("java:/comp/env/jdbc/simmc"); if (ds == null) throw new Exception("Data source not found!"); Connection con = ds.getConnection(); if (con == null) throw new Exception("Failed to get a database connection!"); SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); Schema schema = factory.newSchema(this.xml_inventory_schema); JAXBContext context = JAXBContext.newInstance(CollectedData.class); Unmarshaller unmarshaller = context.createUnmarshaller(); unmarshaller.setSchema(schema); // Strip spaces in the beginning of the xml xmlData = xmlData.replaceAll("^\\s+", ""); // transform the xml string into a InputStream InputStream is = new ByteArrayInputStream(xmlData.getBytes()); // Decode the XML into a Java Object JAXBElement<CollectedData> element = (JAXBElement<CollectedData>) unmarshaller.unmarshal(new StreamSource(is), CollectedData.class); CollectedData collected = element.getValue(); // contact_date = current date Calendar cal = Calendar.getInstance(); java.sql.Date contactDate = new java.sql.Date(cal.getTimeInMillis()); PreparedStatement st = createInventoryStatement(con, collected, contactDate); st.executeUpdate(); List<User> users = collected.getUserHistory().getUser(); int idpoint = collected.getPointInfo().getIdpoint().intValue(); List<Interface> interfaces = collected.getInterfaces().getInterface(); org.postgresql.util.PGobject macaddr = new org.postgresql.util.PGobject(); macaddr.setType("macaddr"); macaddr.setValue(interfaces.get(0).getMacAddress()); for(User user: users) { st = createUserHistoryStatement(con, contactDate, idpoint, macaddr, user.getName(), user.getLogin(), user.getLogout()); st.executeUpdate(); } con.close(); log(INFO, "setInventory(idpoint=" + collected.getPointInfo().getIdpoint() + ", macaddr=" + interfaces.get(0).getMacAddress() + ")"); return "Success"; } catch (Exception e) { log(ERROR, e.getMessage() + " " + xmlData); e.printStackTrace(); return "ERROR: " + e.getMessage(); } } private PreparedStatement createInventoryStatement(Connection con, CollectedData collectedData, java.sql.Date contactDate) throws SQLException, ParseException { final String query = "INSERT INTO telecenter_inventory " + "(contact_date, machine_type, id_point, macaddr, agent_version, " + " os_type, os_distro, os_kernel, " + " processor, memory, " + " disk1_model, disk1_size, disk1_used, " + " disk2_model, disk2_size, disk2_used, " + " extra_hds, mirror_timestamp, amount_users " + ") VALUES " + "(?, ?, ?, ?, ?, " + " ?, ?, ?, " + " ?, ?, " + " ?, ?, ?, " + " ?, ?, ?, " + " ?, ?, ? " + " );"; PreparedStatement st = con.prepareStatement(query); List<Interface> interfaces = collectedData.getInterfaces().getInterface(); Inventory inventory = collectedData.getInventory(); List<Disk> disks = inventory.getDisks().getDisk(); PointInfo pointInfo = collectedData.getPointInfo(); // contact_date st.setDate(1, contactDate); // machine_type if(collectedData.getMachineType().compareTo("client") == 0) st.setInt(2, 0); else st.setInt(2, 1); // idpoint st.setInt(3, pointInfo.getIdpoint().intValue()); // macaddr org.postgresql.util.PGobject macaddr = new org.postgresql.util.PGobject(); macaddr.setType("macaddr"); macaddr.setValue(interfaces.get(0).getMacAddress()); st.setObject(4, macaddr); // versao st.setString(5, collectedData.getAgentVersion()); // os_type st.setString(6, inventory.getOs()); // os_distro st.setString(7, inventory.getDistro()); // os_kernel st.setString(8, inventory.getKernel()); // processor st.setString(9, inventory.getProcessor()); // memory st.setInt(10, inventory.getMemory().intValue()); // disk1_model st.setString(11, disks.get(0).getModel()); // disk1_size st.setInt(12, disks.get(0).getSize().intValue()); // disk1_used st.setInt(13, disks.get(0).getUsed().intValue()); if (disks.size() > 1) { // disk2_model st.setString(14, disks.get(1).getModel()); // disk2_size st.setInt(15, disks.get(1).getSize().intValue()); // disk2_used st.setInt(16, disks.get(1).getUsed().intValue()); } else { // disk2_model st.setNull(14, Types.VARCHAR); // disk2_size st.setNull(15, Types.INTEGER); // disk2_used st.setNull(16, Types.INTEGER); } // extra_hds st.setInt(17, (disks.size() > 2) ? (disks.size() - 2) : 0); // mirrors_timestamp if(collectedData.getMirrorsTimestamp().compareTo(" ") == 0) st.setTimestamp(18, null); else { SimpleDateFormat dt = new SimpleDateFormat("EEE MMM dd hh:mm:ss zzz yyyy", Locale.US); Date ts = dt.parse(collectedData.getMirrorsTimestamp()); st.setTimestamp(18, new java.sql.Timestamp(ts.getTime())); } // user_count st.setInt(19, pointInfo.getUserCount().intValue()); return st; } private PreparedStatement createUserHistoryStatement(Connection con, java.sql.Date contactDate, int id_point, Object macaddr, String name, String login, String logout) throws SQLException { final String query = "INSERT INTO telecenter_user " + "(contact_date, id_point, macaddr, name, login, logout) VALUES " + "(?, ?, ?, ?, ?, ?);"; PreparedStatement st = con.prepareStatement(query); st.setDate(1, contactDate); st.setInt(2, id_point); st.setObject(3, macaddr); st.setString(4, name); try { st.setTime(5, java.sql.Time.valueOf(login)); } catch (Exception e) { st.setTime(5, null); } try { st.setTime(6, java.sql.Time.valueOf(logout)); } catch (Exception e) { st.setTime(6, null); } return st; } /** * Receive an XML string which has the inventory data to be parsed and * inserted into database. Return "Success" string if insertion operation * is successful. Any other errors will throw exceptions. * * @author Eduardo Luis Buratti * @param xmlData XML string of inventory * @return String */ public String setNetUsage(String xmlData) { try { InitialContext cxt = new InitialContext(); DataSource ds = (DataSource) cxt.lookup("java:/comp/env/jdbc/simmc"); if (ds == null) throw new Exception("Data source not found!"); Connection con = ds.getConnection(); if (con == null) throw new Exception("Failed to get a database connection!"); SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); Schema schema = factory.newSchema(this.xml_net_usage_schema); JAXBContext context = JAXBContext.newInstance(NetCollectedData.class); Unmarshaller unmarshaller = context.createUnmarshaller(); unmarshaller.setSchema(schema); // Strip spaces in the beginning of the xml xmlData = xmlData.replaceAll("^\\s+", ""); // transform the xml string into a InputStream InputStream is = new ByteArrayInputStream(xmlData.getBytes()); // Decode the XML into a Java Object JAXBElement<NetCollectedData> element = (JAXBElement<NetCollectedData>) unmarshaller.unmarshal(new StreamSource(is), NetCollectedData.class); NetCollectedData netCollectedData = element.getValue(); List<Interface> interfaces = netCollectedData.getInterfaces().getInterface(); // contact_date = current date Calendar cal = Calendar.getInstance(); java.sql.Date contactDate = new java.sql.Date(cal.getTimeInMillis()); // macaddr org.postgresql.util.PGobject macaddr = new org.postgresql.util.PGobject(); macaddr.setType("macaddr"); macaddr.setValue(interfaces.get(0).getMacAddress()); List<NetUse> netUses = netCollectedData.getBandwidthUsage().getNetuse(); for(NetUse netUse : netUses) { PreparedStatement st = createNetUsageStatement(con, contactDate, netCollectedData.getIdPoint(), (Object)macaddr, netUse.getDate(), netUse.getTime(), netUse.getRx().getRxBytes(), netUse.getRx().getRxPackets(), netUse.getTx().getTxBytes(), netUse.getTx().getTxPackets()); st.executeUpdate(); } con.close(); log(DEBUG, "setNetUsage(idpoint=" + netCollectedData.getIdPoint() + ", macaddr=" + interfaces.get(0).getMacAddress() + ")"); return "Success"; } catch (Exception e) { log(ERROR, e.getMessage() + " " + xmlData); e.printStackTrace(); return "ERROR: " + e.getMessage(); } } private PreparedStatement createNetUsageStatement(Connection con, java.sql.Date contactDate, BigInteger idpoint, Object macaddr, String collect_date, String collect_time, long down_bytes, BigInteger down_packages, long up_bytes, BigInteger up_packages) throws SQLException { final String query = "INSERT INTO net_usage " + "(contact_date, id_point, macaddr, collect_date, collect_time, " + "down_bytes, down_packages, up_bytes, up_packages, ip, city_code) VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; PreparedStatement st = con.prepareStatement(query); st.setDate(1, contactDate); st.setInt(2, idpoint.intValue()); st.setObject(3, macaddr); st.setDate(4, java.sql.Date.valueOf(collect_date)); st.setTime(5, java.sql.Time.valueOf(collect_time)); st.setLong(6, down_bytes); st.setInt(7, down_packages.intValue()); st.setLong(8, up_bytes); st.setInt(9, up_packages.intValue()); st.setObject(10, null); st.setString(11, null); return st; } }