Wednesday, December 26, 2012

java - Calendar.java and GregorianCalendar.java - how to by a full implementation


Some day, while I was implementing a DAO layer,  it was required to create an order which the dispatch date was the order date plus 7 days.
Some additional business rules like postponing due to weekend, holidays, etc. added additional complexity.
So, I decided to create a CalendarSvc (calendar service) class to handle the required issues concerning date and time.

The following class offers that and many other facilities to support many date/time operations.

For instance:

    /**
     * Obtains the dispatch date.
     * @return date plus dispatch period.
     */
    public static Date dispatchDate(Date date) {
        CalendarSvc dispatchDate = new CalendarSvc(date.getTime() + (dispatchPeriod * CalendarSvc.DAYMSEC));
        return
dispatchDate.date();
    }


where  dispatchPeriod is a variable defined on your config.ini that holds the number of days which is supposed to be dispatched (in this case was:  dispatchPeriod = 7)

There are other examples on the header comment.

You're gonna find some references to another classes, but they are self-explanatory and I suppose that their name is enough to suggest the simple extra implementation required.


CalendarSvc.java
------------------------------------------------------------------------------------------------------------------

package javaLib.time.calendar;

import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.StringTokenizer;
import java.util.TimeZone;

import javaLib.services.StrSvc;
import javaLib.time.DateTime;

/**
 * javaLib.time.calendar.Days2Calendar.java

 * project: javaLib

 *

 * target: Calendar services using GregorianCalendar.

 *

 *

 *
 * notes:
 *

 * Example#1 - difference between:
 *
 *    Date date = CalendarSvc.dmy("31/12/2012", "/").date();
 *
 * 
 *        CalendarSvc before = new CalendarSvc();
 *     try {
 *       Thread.sleep(10);
 *     } catch (InterruptedException e) {
 *       e.printStackTrace();
 *     }
 *     CalendarSvc after = new CalendarSvc();
 *     System.out.println(before.diffMillisec(after.getDate()));
 *     // same as:
 *     System.out.println(after.getDate().getTimeInMillis() - before.getDate().getTimeInMillis());
 * 
 *     CalendarSvc before = new CalendarSvc();
 *     System.out.println(before.getDate());
 *     System.out.println(before.ymdDate());
 *     System.out.println(before.ymdTimeDate());
 *     System.out.println(before.getDate().getTimeInMillis());
 * 
 *     CalendarSvc after = new CalendarSvc(2012,12,31);
 *     System.out.println(after.getDate());
 *     System.out.println(after.ymdTimeDate());
 *     System.out.println(after.getDate().getTimeInMillis());
 * 
 *     Long diff = before.diffMillisec(after.getDate());
 *     System.out.println("difference in milliseconds = " + diff);
 *     System.out.println("difference in days = " + CalendarSvc.millisec2days(diff));
 *     System.out.println("difference in days = " + before.daysBetween(after.getDate()));
 * 
 *     System.out.println("\n--- 1");
 *     Date d1 = new Date();
 *     long t = d1.getTime() + 3600000;
 *     Date d2 = new Date();
 *     d2.setTime(t);
 *     System.out.println("d1 = " + d1);
 *     System.out.println("d1.getTime() = " + d1.getTime());
 *     System.out.println("d2 = " + d2);
 *     System.out.println("d2.getTime() = " + d2.getTime());
 *     System.out.println("t = " + t);
 *
 *     CalendarSvc calendarSvc = CalendarSvc.dmy("12/08/2012", "/");
 *     System.out.println(calendarSvc.dmyDate());
 *     
 *     
 * Example#2 - using Date():
 *  
 *     System.out.println("\n--- 2");
 *     
 *     Date d1 = new Date();
 *     CalendarSvc date1 = new CalendarSvc(d1.getTime());
 *     System.out.println(date1.getDate());
 *     System.out.println(date1.ymdTimeDate());
 *     System.out.println(date1.getDate().getTimeInMillis());
 *     
 * 
 * Example#3 - adding days and difference between:
 * 
 *     System.out.println("\n--- 3");
 *     
 *     CalendarSvc date3 = new CalendarSvc();
 *     System.out.println("today = " + date3.ymdTimeDate());
 *     System.out.println(date3.dayOfWeek());
 *     System.out.println(date3.getDate().getTimeInMillis());
 *     
 *     int days = 7;
 *     date3.addDays(days);
 *     
 *     System.out.println("today + " + days + " = " + date3.ymdTimeDate());
 *     System.out.println(date3.ymdTimeDate());
 *     System.out.println(date3.dayOfWeek());
 *     System.out.println(date3.getDate().getTimeInMillis());
 * 

 *
 * @see prj:
 * @author alsdias@yahoo.com.br
 * @version v.1.0.0 - Dec 26, 2012
 */
public class CalendarSvc implements ICalendarSvc {

    protected GregorianCalendar date = null;
    protected int year = 0;
    protected int month = 0;
    protected int day = 0;
    protected int hour = 0;
    protected int minute = 0;
    protected int second = 0;
    protected long millisec = 0L;
    protected Locale locale = null;
    protected TimeZone timezone = null;
   
   
    /** one day in milliseconds */
    public static final long DAYMSEC = 86400000L; // 24L * 60L * 60L * 1000L;
   
    private String dateDelimiter = "/";
    private String timeDelimiter = ":";

    protected DateFormatSymbols symbols;
    protected String[] shortMonthList, monthList, weekdayList;
   
   
    private void setDefaults() {
        locale = Locale.getDefault();
        timezone = TimeZone.getDefault();
        date = new GregorianCalendar(timezone, locale);
    }
   
    /**
     * Common initialization procedures.
     */
    private void init() {
        year = date.get(GregorianCalendar.YEAR);
        month = date.get(GregorianCalendar.MONTH) + 1;
        day = date.get(GregorianCalendar.DAY_OF_MONTH);
        hour = date.get(GregorianCalendar.HOUR_OF_DAY);
        minute = date.get(GregorianCalendar.MINUTE);
        second = date.get(GregorianCalendar.SECOND);
        millisec = date.get(GregorianCalendar.MILLISECOND);
        symbols = ((SimpleDateFormat)DateFormat.getInstance()).getDateFormatSymbols();
        monthList = symbols.getMonths();
        shortMonthList = symbols.getShortMonths();
        weekdayList = symbols.getWeekdays();
    }
    /**
     * Constructor using default values for timezone and locale.
     */
    public CalendarSvc() {
        setDefaults();
        init();
    }

    /**
     * Constructor for specific locale.
     * @param locale
     */
    public CalendarSvc(Locale locale) {
        this.locale = locale;
        timezone = TimeZone.getDefault();
        date = new GregorianCalendar(timezone, locale);
        init();
    }
   
    /**
     * Constructor using specific timezone and locale.
     */
    public CalendarSvc(TimeZone timezone, Locale locale) {
        locale = Locale.getDefault();
        timezone = TimeZone.getDefault();
        date = new GregorianCalendar(timezone, locale);
        init();
    }
   
    /**
     * Constructor for creating a specific date.
     * @param year
     * @param month_
     * @param day day of month
     */
    public CalendarSvc(int year, int month, int day) {
        setDefaults();
        date.set(GregorianCalendar.YEAR, year);
        date.set(GregorianCalendar.MONTH, month - 1);
        date.set(GregorianCalendar.DAY_OF_MONTH, day);
        init();
    }

    /**
     * Constructor for creating a specific date and time.
     * @param year
     * @param month
     * @param day
     * @param hour
     * @param minute
     * @param sec
     */
    public CalendarSvc(int year, int month, int day, int hour, int minute, int sec) {
        setDefaults();
        date.set(GregorianCalendar.YEAR, year);
        date.set(GregorianCalendar.MONTH, month-1);
        date.set(GregorianCalendar.DAY_OF_MONTH, day);
        date.set(GregorianCalendar.HOUR_OF_DAY, hour);
        date.set(GregorianCalendar.MINUTE, minute);
        date.set(GregorianCalendar.SECOND, sec);
        init();
    }

    public CalendarSvc(long milliseconds) {
        setDefaults();
        Date time = new Date();
        time.setTime(milliseconds);
        date.setTime(time);
        init();
    }
   
/*-----------------------------------------------------------------------------------------------------------------------
 ***SERVICES
-----------------------------------------------------------------------------------------------------------------------*/

    public String dayOfWeek() {
        return date.getDisplayName(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.ALL_STYLES, locale);
    }
   
    /**
     * Adds a number of days to the date.
     * @param number
     */
    public void addDays(int number) {
        Date time = new Date();
        time.setTime(time.getTime() + number * CalendarSvc.DAYMSEC);
        CalendarSvc newcal = new CalendarSvc(time.getTime());
        this.date = newcal.getDate();
        init();
    }
   
   
    /**
     * Obtains the days between the current date and another.
     * @param other
     * @return
     */
    public long daysBetween(Calendar other) {
        return CalendarSvc.millisec2days(other.getTimeInMillis() - this.date.getTimeInMillis());
    }
   
   
    /**
     * Returns YEAR/MONTH/DAY if default delimiter is used.
     * @return
     */
    public String ymdDate() {
        return year + dateDelimiter + month + dateDelimiter + day;
    }
   
    /**
     * Obtains CalendarSvc from a YMD formal date string.
     * Ex: ymd("2012/08/12", "/");
     * @param sdate
     * @param delimiter
     * @return
     */
    public static CalendarSvc ymd(String sdate, String delimiter) {
        StringTokenizer stokens = new StringTokenizer(sdate, delimiter);
        return new CalendarSvc(Integer.valueOf(stokens.nextToken()), Integer.valueOf(stokens.nextToken()), Integer.valueOf(stokens.nextToken()));
    }
   
    /**
     * Obtains CalendarSvc from a DMY formal date string.
     * Ex: ymd("12/08/2012", "/");
     * @param sdate
     * @param delimiter
     * @return
     */
    public static CalendarSvc dmy(String sdate, String delimiter) {
        StringTokenizer stokens = new StringTokenizer(sdate, delimiter);
        int year = Integer.valueOf(stokens.nextToken());
        int month = Integer.valueOf(stokens.nextToken());
        int day = Integer.valueOf(stokens.nextToken());
        return new CalendarSvc(day, month, year);
    }
   
    /**
     * Returns DAY/MONTH/YEAR if default delimiter is used.
     * @return
     */
    public String dmyDate() {
        return day + dateDelimiter + month + dateDelimiter + year;
    }
   
    /**
     * Returns YEAR/MONTH/DAY HOUR:MINUTE:SECOND:MILLISECOND if default delimiters are used.
     * @return
     */
    public String ymdTimeDate() {
        return year + dateDelimiter + month + dateDelimiter + day + " " + hour + timeDelimiter + minute + timeDelimiter + minute + timeDelimiter + millisec;
    }

   
    /**
     * Returns the present instant as follow: YYYYMMDD_hh:mm:ss:SSS).
     * Example: 080381_17:35:01:897
     * @param language
     * @param country
     * @return timestamp format as follow: yyMMDD_H:mm:ss:SSS
     */
    public static String timestamp(String language, String country) {
        Date today = new Date();   
        Locale locale = new Locale(language, country);
        SimpleDateFormat formatter = new SimpleDateFormat("yyMMDD_H:mm:ss:SSS", locale);
        String output = formatter.format(today);
        return output;
    }

    /**
     * Returns the present instant as follow: YYYYMMDD_hh:mm:ss:SSS).
     * Example: 080381_17:35:01:897
     * @return timestamp format as follow: yyMMDD_H:mm:ss:SSS
     */
    public String timestamp() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyMMDD_H:mm:ss:SSS", locale);
        String output = formatter.format(date.getTime());
        return output;
    }

   
    /**
     * Returns the present instant according to format parameter.
     * Example: 080381_17:35:01:897
     * @param language
     * @param country
     * @param format Sun's SimpleDateFormat string pattern. For instance: yyMMDD_H:mm:ss:SSS
     * @return timestamp formatted. If null or empty, assumes default = "yyMMDD_H:mm:ss:SSS"
     */
    public static String timestamp(String language, String country, String format) {
        if(format == null || format.isEmpty()) format = "yyMMDD_H:mm:ss:SSS";
        Date today = new Date();   
        Locale locale = new Locale(language, country);
        SimpleDateFormat formatter = new SimpleDateFormat(format, locale);
        String output = formatter.format(today);
        return output;
    }
   
    /**
     * Returns the present instant according to format parameter.
     * Example: 080381_17:35:01:897
     * @param format Sun's SimpleDateFormat string pattern. For instance: yyMMDD_H:mm:ss:SSS
     * @return timestamp formatted. If null or empty, assumes default = "yyMMDD_H:mm:ss:SSS"
     */
    public String timestamp(String format) {
        if(format == null || format.isEmpty()) format = "yyMMDD_H:mm:ss:SSS";
        SimpleDateFormat formatter = new SimpleDateFormat(format, locale);
        String output = formatter.format(date.getTime());
        return output;
    }
   
    /**
     * Returns a timestamp string without the milliseconds, formatted as follow if delimiter = &quot;_&quot;:<br>
     * YYYYMMDD_hhmmss
     * @param timestamp formatted as follow: YYYYMMDD_hhmmss_msec<br>
     * If null or empty returns an empty string. If size &lt; 17 or missing time returns exception.
     * @param delimiter the string used to delimiter the date fields.<br>
     * If null or empty, assumes default = "/".
     * @return For instance, if delimiter = &quot;_&quot;, returns YYYYMMDD_hhmmss .<br>
     * @throws StrException
     */
    public static String getTimestampMinusMsec(String timestamp, String delimiter) throws Exception {
        String exceptionMsg = "[ERROR]: javaLib.time.TimeSvc.getTimestampMinusMsec";
        if(timestamp == null || timestamp.isEmpty()) return "";
        if(timestamp.length() < 17) throw new Exception(exceptionMsg + ": invalid timestamp format - length = " + timestamp.length());
        if(delimiter == null || delimiter.isEmpty()) delimiter = "/";
        ArrayList<String> fields = StrSvc.str2arrayList(timestamp, delimiter);
        if(fields.size() < 2) throw new Exception(exceptionMsg + ": invalid timestamp format - fields size = " + fields.size());
        return fields.get(0) + "_" + fields.get(1);
    }

    /**
     * Returns a timestamp string without the milliseconds, formatted as follow if delimiter = &quot;_&quot;:<br>
     * YYYYMMDD_hhmmss
     * @param timestamp formatted as follow: YYYYMMDD_hhmmss_msec<br>
     * If null or empty returns an empty string. If size &lt; 17 or missing time returns exception.
     * @param delimiter the string used to delimiter the date fields.<br>
     * If null or empty, assumes default = "/".
     * @return For instance, if delimiter = &quot;_&quot;, returns YYYYMMDD_hhmmss .<br>
     * @throws StrException
     */
    public String getTimestampMinusMsec(String timestamp) throws Exception {
        String exceptionMsg = "[ERROR]: javaLib.time.TimeSvc.getTimestampMinusMsec";
        if(timestamp == null || timestamp.isEmpty()) return "";
        if(timestamp.length() < 17) throw new Exception(exceptionMsg + ": invalid timestamp format - length = " + timestamp.length());
        ArrayList<String> fields = StrSvc.str2arrayList(timestamp, dateDelimiter);
        if(fields.size() < 2) throw new Exception(exceptionMsg + ": invalid timestamp format - fields size = " + fields.size());
        return fields.get(0) + "_" + fields.get(1);
    }


    /**
     * Converts time in milliseconds since Epoch to timestamp.
     * @param millisec time in milliseconds since Epoch.
     * @return timestamp in the format: YYYYMMDD_hhmmss_msec <br>
     * If null or empty argument, returns empty string.
     * @throws StrException
     */
    public static String millisecToTimestamp(String millisec) throws Exception {
        if(millisec == null || millisec.isEmpty()) return "";
        int timekey_ = 0;
        try {
            timekey_ = Integer.parseInt(millisec);
        } catch (Exception e) {
            throw new Exception("[exception]: br.gov.datasus.synopsis.millisecToTimestamp: invalid millisec value");
        }
        DateTime dt = new DateTime(null, timekey_);
        return dt.timestamp();
    }

    /**
     * Converts a timestamp into milliseconds since Epoch.
     * @param timestamp in the format: YYYYMMDD_hhmmss_msec
     * @return time in milliseconds since Epoch.
     * @throws StrException
     */
    public static long timestampToMillisec(String timestamp) throws Exception {
        DateTime dt = new DateTime(timestamp);
        return dt.get_timeInMillis();
    }
   
    /**
     * Converts to milliseconds.
     * @param dateParts array where array[0]=YYYY, array[1]=MM, array[2]=DD.
     * @return milliseconds from the Epoch(01/01/1970).
     * @throws StrException
     */
    public Long milliseconds(int[] dateParts) throws Exception {
        if(dateParts == null || dateParts.length < 3) throw new Exception("[ERROR]: invalid syntax: missing date or values");
        Calendar cal = Calendar.getInstance(locale);
            cal.set(dateParts[0], dateParts[1], dateParts[2]);  
        return cal.getTimeInMillis();
    }


    /**
     * Converts to milliseconds a string of date using a format pattern.
     * @param s_date
     * @param pattern
     * @return milliseconds from the Epoch(01/01/1970).
     * @throws StrException
     */
    public static Long milliseconds(String s_date, String pattern) throws Exception {
        String errorMsg = "[ERROR]: invalid syntax: missing date or values";
        if(StrSvc.isNullEmpty(s_date) || StrSvc.isNullEmpty(pattern))
            throw new Exception(errorMsg);
        try {
            Date date = new SimpleDateFormat(pattern).parse(s_date);
            return date.getTime();
        } catch (ParseException e) {
            throw new Exception(errorMsg + " due to: " + e.getMessage());
        }
    }

    /**
     * Converts milliseconds to a time string according to its patterns.
     * @param milliseconds
     * @param pattern
     * @return time string
     */
    public static String time(Long milliseconds, String pattern) {
        SimpleDateFormat formato = new SimpleDateFormat(pattern);  
        return formato.format(new Date(milliseconds));
    }
   

    /**
     * Conversion of milliseconds to days.
     * @param millisec
     * @return
     */
    public static long millisec2days(Long millisec) {
        return millisec / 86400000;
    }
   
    /**
     * Calculates in milliseconds the residual time in the year (from supplied date to the end of the year).
     * @param date the present date.
     * @return residual time in milliseconds.
     */
    public static long residualMillisecInYear(Calendar date) {
        GregorianCalendar lastday = new GregorianCalendar(date.get(GregorianCalendar.YEAR), 12, 31);
        return lastday.getTimeInMillis() - date.getTimeInMillis();
    }

    /**
     * Calculates the time difference compared to another in milliseconds.
     * @param now
     * @param other
     * @return difference in milliseconds.
     */
    public long diffMillisec(Calendar other) {
        return other.getTimeInMillis() - date.getTimeInMillis();
    }
   
   
    /**
     * Calculates the time difference between two dates in milliseconds.
     * @param now
     * @param after
     * @return difference in milliseconds.
     */
    public static long diffMillisec(Calendar now, Calendar after) {
        return after.getTimeInMillis() - now.getTimeInMillis();
    }
   
   
    /**
     * Converts days to number of years, months and days.
     *
     * @param days
     * @return
     */
    public Integer[] days2calendar(int days) {
        int max_year = date.getActualMaximum(GregorianCalendar.DAY_OF_YEAR);
        int max_month = date.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
        Integer[] ymd = {0,0,0};
        ymd[0] = (days >= max_year) ? days/max_year : 0;
        int m = days - (ymd[0] * max_year);
        ymd[1] = (m >= max_month) ? m/max_month : 0;
        ymd[2] = m - (ymd[1] * max_month);
        return ymd;
    }

    /**
     * Straight accessor for Date object.
     * @return Date object.
     */
    public Date date() {
        return date.getTime();
    }

    /**
     * Obtains the short month notation.<br>
     * Jan = 1, Feb = 2, ... Dec = 12.
     * @param index 1-12
     * @return short month notation, otherwise empty.
     */
    @Override
    public String shortMonth(int index) {
        if(index < 1 || index > 13) return "";
        return shortMonthList[index];
    }
   
    /**
     * Obtains the month full notation.<br>
     * January = 1, February = 2, ... December = 12.
     * @param index 1-12
     * @return full month notation, otherwise empty.
     */
    @Override
    public String month(int index) {
        if(index < 1 || index > 13) return "";
        return monthList[index];
    }
   
   
/*-----------------------------------------------------------------------------------------------------------------------
 ***GETTERS/SETTERS
-----------------------------------------------------------------------------------------------------------------------*/
   
   
    public int getHour() {
        return hour;
    }

    public GregorianCalendar getDate() {
        return date;
    }
    public void setDate(GregorianCalendar date) {
        this.date = date;
    }
    public int getYear() {
        return year;
    }
    public void setYear(int year) {
        this.year = year;
    }
    public int getMonth() {
        return month;
    }
    public void setMonth(int month) {
        this.month = month;
    }
    public int getDay() {
        return day;
    }
    public void setDay(int day) {
        this.day = day;
    }
    public void setHour(int hour) {
        this.hour = hour;
    }

    public int getMinute() {
        return minute;
    }

    public void setMinute(int minute) {
        this.minute = minute;
    }

    public int getSecond() {
        return second;
    }

    public void setSecond(int second) {
        this.second = second;
    }

    public long getMillisec() {
        return millisec;
    }
    public void setMillisec(long millisec) {
        this.millisec = millisec;
    }
   
    public String getDateDelimiter() {
        return dateDelimiter;
    }
    public void setDateDelimiter(String dateDelimiter) {
        this.dateDelimiter = dateDelimiter;
    }
    public String getTimeDelimiter() {
        return timeDelimiter;
    }
    public void setTimeDelimiter(String timeDelimiter) {
        this.timeDelimiter = timeDelimiter;
    }
   
    /*-----------------------------------------------------------------------------------------------------------------------
     ***GETTERS/SETTERS
    -----------------------------------------------------------------------------------------------------------------------*/

    public DateFormatSymbols getSymbols() {
        return symbols;
    }

    public void setSymbols(DateFormatSymbols symbols) {
        this.symbols = symbols;
    }

    public String[] getMonthList() {
        return monthList;
    }

    public void setMonthList(String[] monthList) {
        this.monthList = monthList;
    }

    public String[] getWeekdayList() {
        return weekdayList;
    }

    public void setWeekdayList(String[] weekdayList) {
        this.weekdayList = weekdayList;
    }


    public String[] getShortMonthList() {
        return shortMonthList;
    }


    public void setShortMonthList(String[] shortMonthList) {
        this.shortMonthList = shortMonthList;
    }

    @Override
    public Locale getLocale() {
        return locale;
    }

    @Override
    public void setLocale(Locale locale) {
        this.locale = locale;
    }

    /**
     * For testing purpose.
     * @param args
     */
//    public static void main(String[] args) {
//       
//    }
   
}

mysql - error 1005 (hy000) at line ... can't create table

Creating the database:
 
$ mysql -uroot -pmysql < my_tester_createdb_2.sql

Returns:
ERROR 1005 (HY000) at line 202: Can't create table './tester/#sql-d2d_146.frm' (errno: 150)


Solution

Search for a foreign key reference mistake like:

 - incompatible types
 - unsigned (when it shouldn't )







hibernate error: path expected for join

To ORM (Object Relational Mapping), a path is a reference inside the target object that leads to its respective associations.

For instance, this WRONG HQL statement:

select prod.nome, cat.nome from ProductVO as prod join CategoryVO as cat

causes the exception:

app.exception.DaoException: [SYSTEM]: Path expected for join! [select prod.nome, cat.nome from app.model.persistence.hbn.vo.ProductVO as prod join
CategoryVO as cat]


The mistake is that the statement was created thinking as it were SQL way of doing things.

But, the ORM way of doing things is:

select prod.nome, cat.nome from ProductVO as prod join prod.CategoryVO as cat

The path is supplied by prod.CategoryVO as cat, which is the referenced object.

Wednesday, December 5, 2012

hibernate: java.lang.noclassdeffounderror: com/mchange/v2/c3p0/datasources

Problem

If you are using c3p0 connection pool for hibernate, then you probably have
on the hibernate.cfg.xml file the following configuration:

<!-- c3p0 connection pool (use the built-in) -->
  <property name="connection.pool_size">c3p0</property>
  <property name="c3p0.min_size">5</property>
  <property name="c3p0.max_size">20</property>
  <property name="c3p0.timeout">1800</property>
  <property name="c3p0.max_statements">50</property>


When you run the application, it throws an exception like below:



21:03:25,016  INFO C3P0ConnectionProvider:82 - Connection properties: {user=root, password=****}
21:03:25,016  INFO C3P0ConnectionProvider:85 - autocommit mode: false
21:03:25,023  WARN C3P0ConnectionProvider:210 - Both hibernate-style property 'hibernate.c3p0.max_size' and c3p0-style property 'c3p0.max_size' have
been set in hibernate.properties.
Hibernate-style property 'hibernate.c3p0.max_size' will be used and c3p0-style property 'c3p0.max_size' will be ignored!
21:03:25,023  WARN C3P0ConnectionProvider:210 - Both hibernate-style property 'hibernate.c3p0.min_size' and c3p0-style property 'c3p0.min_size' have
been set in hibernate.properties.
Hibernate-style property 'hibernate.c3p0.min_size' will be used and c3p0-style property 'c3p0.min_size' will be ignored!
21:03:25,024  WARN C3P0ConnectionProvider:210 - Both hibernate-style property 'hibernate.c3p0.timeout' and c3p0-style property 'c3p0.timeout' have
been set in hibernate.properties.
Hibernate-style property 'hibernate.c3p0.timeout' will be used and c3p0-style property 'c3p0.timeout' will be ignored!
21:03:25,024  WARN C3P0ConnectionProvider:210 - Both hibernate-style property 'hibernate.c3p0.max_statements' and c3p0-style property
'c3p0.max_statements' have been set in hibernate.properties.Hibernate-style property 'hibernate.c3p0.max_statements' will be used and c3p0-style property 'c3p0.max_statements' will be ignored!
Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: com/mchange/v2/c3p0/DataSources
Exception in thread "main" java.lang.ExceptionInInitializerError
  at ipg.model.persistence.hbn.HbnDaoFactory.<clinit>(HbnDaoFactory.java:43)
  at test.db.AdminVO_test.showList(AdminVO_test.java:120)
  at test.db.AdminVO_test.main(AdminVO_test.java:46)
Caused by: java.lang.NoClassDefFoundError: com/mchange/v2/c3p0/DataSources
  at org.hibernate.connection.C3P0ConnectionProvider.configure(C3P0ConnectionProvider.java:154)
  at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:124)
  at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:56)
  at org.hibernate.cfg.SettingsFactory.createConnectionProvider(SettingsFactory.java:414)
  at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:62)
  at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2073)
  at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1298)
  at ipg.model.persistence.hbn.HbnDaoFactory.<clinit>(HbnDaoFactory.java:39)
  ... 2 more
Caused by: java.lang.ClassNotFoundException: com.mchange.v2.c3p0.DataSources
  at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
  at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
  ... 10 more




Solution

Missing  the c3p0 jar files on the project's build path.
Download the jar file, for instance:
c3p0-0.9.1.2.jar

Monday, November 19, 2012

SEVERE: The system cannot infer the transport information from the http://localhost:8080/axis2/services/


Issue
 
Web Services that returns the following exception:

SEVERE: The system cannot infer the transport information from the  http://localhost:8080/axis2/services/DataService URL.
Exception in thread "main" org.apache.axis2.AxisFault: The system cannot infer the transport information from the  http://localhost:8083/axis2/services/DataService URL.

 
Solution

If the URL is really correct, try checking the spaces on the url.

Example of a undesirable initial space causing the problem (yellow):
String url = " http://localhost:8080/axis2/services/DataService";

To avoid such problem, instead of:
DataServiceStub service = new DataServiceStub(url)

do:
DataServiceStub service = new DataServiceStub(url.trim());

Thursday, November 15, 2012

Cannot resolve the name '...' to a(n) 'type definition' component


Suppose you are validating the a xml file against a XML Schema (a .xsd file), and an exception message returns like this:


org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'createNewAdRequest' to a(n) 'type definition' component.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)

Check the if the type declaration is accessible, in order words, has the same scope.


For instance, here is the test.xml file:

<ClassifiedList>
    <ClassifiedAd>
        <id>1234</id>
        <content>
            Vintage 1963 T-Bird.  Less than 300 miles.
            Driven by my daughter until I took it away.
            Serious inquires only. 555-3264 after 7 PM.
        </content>
        <endDate>4/15/2007</endDate>
        <startDate>4/1/2007</startDate>
        <createNewAdRequest>
            <content>YYY</content>
            <endDate>YYY</endDate>
        </createNewAdRequest>
    </ClassifiedAd>  
</ClassifiedList>


And here the respctive XML Schema file - test.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element type="ClassifiedList" name="ClassifiedList" />
    <xs:complexType name="ClassifiedList">
      <xs:sequence>
        <xs:element minOccurs="0" type="ClassifiedAd"
                        name="ClassifiedAd" maxOccurs="unbounded" />
      </xs:sequence>
    </xs:complexType>

    <xs:element type="ClassifiedAd" name="ClassifiedAd" />
    <xs:complexType name="ClassifiedAd">
      <xs:sequence>
        <xs:element type="xs:int" name="id" />
        <xs:element type="xs:string" name="content" />
        <xs:element type="xs:string" name="endDate" />
        <xs:element type="xs:string" name="startDate" />
        <xs:element type="createNewAdRequest" name="createNewAdRequest" maxOccurs="unbounded" />
      </xs:sequence>
    </xs:complexType>
       
    <xs:element name="createNewAdRequest">
        <xs:complexType name="createNewAdRequest">
            <xs:sequence>
                <xs:element type="xs:string" name="content" />
                <xs:element type="xs:string" name="endDate" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
   
</xs:schema>


The text highlighted in blue defines a new type under its element scope.
So, it is not accessible from outside.
Switch the blue text by the orange below, where the complex type is defined in the same scope of  <ClassifiedList> element.
       
        <xs:complexType name="createNewAdRequest">
            <xs:sequence>
                <xs:element type="xs:string" name="content" />
                <xs:element type="xs:string" name="endDate" />
            </xs:sequence>
        </xs:complexType>
   

Tuesday, November 13, 2012

Maven and The "exception in thread main java.lang.noclassdeffounderror"



This a tip for that situation when everything was checked and looks fine but eventually doesn't work!  : )

Short story
If you are sure that your configuration is correct and has also tried everything, then try creating a new project from scratch and after migrate the code.



Long story

Issue:

Output:

Exception in thread "main" java.lang.NoClassDefFoundError: validation/schema/XasValidator
Caused by: java.lang.ClassNotFoundException: validation.schema.XasValidator
  at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
  at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: validation.schema.XasValidator. Program will exit.



Solution

After checking all possible configurations in project, including of course the pom.xml file, the problems still remained.

The solution came from creating a new project from scratch.

mkdir xalValidator
cd xalValidator
mvn archetype:create -DgroupId=com.adr -DartifactId=xalValidator -DpackageName=validator.schema -Dversion=1.0

After I copied the pom.xml file from the deffective project to the new one.
Then, I migrated the code from the old to the new project.
Finally I tested the project generating the jar file.
Yesss, success.

Sunday, November 4, 2012

Improving The Site Security - Checking .asc files with PGP (GPG)


This example shows step by step how to check security issues about a downloaded file applying concepts exposed on Apache's tutorial .


If you just want to test integrity, a simpler alternative is using MD5 or SHA, but checking both, integrity and signature, offers a better security solution.
This makes sense when downloading security libraries to a secure service or web service.


How can you assure that your site is secure if its libraries are not checked at all?
Just because you use SSH and all the stuff about, how can you be sure that the libraries were not tampered and they are exactly what you expect to be?
So, it's necessary to expend some time to make sure and construct security from the basis.

If downloading a Apache file, you'll probably has already seen on the download page, the following:

It is essential that you verify the integrity of the downloaded files using the PGP or MD5 signatures.
The PGP signatures can be verified using PGP or GPG.
First download the KEYS as well as the asc signature file for the relevant distribution.
Make sure you get these files from the main distribution site, rather than from a mirror. Then verify the signatures using

% pgpk -a KEYS
% pgpv downloaded_file.asc
or
% pgp -ka KEYS
% pgp downloaded_file.asc
or
% gpg --import KEYS
% gpg --verify downloaded_file.asc




On the procedure above, you import the keys (KEYS) in order to be able to verify the downloaded files and check the files' integrity.
 
Nevertheless, suppose that you don't have the keys from KEYS file, or yet if you'd like to check further, considering the message returned by the --verify option:
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.



Below, it's shown an example of a procedure based on "web of trust".
Although long at first sight, many steps done once will not be repeated twice. The data collected is maintained and the next steps become faster and easier.
First time is a first time... well, you just know how it works!


This example uses GnuPG, but the concepts are the same, so feel free to work with your favorite environment and tool.

From the documentation we have:
gpg is the OpenPGP part of the GNU Privacy Guard (GnuPG). 
It is a tool to provide digital encryption and signing services  using  the  OpenPGP      standard.
...
The gpg command is the standalone version of gpg.  
For desktop use you should consider using gpg2.

The example uses two files downloaded from wss4j project which represents a possible and real use case when a developer is creating secure solutions.

The version downloaded by this time were:

wss4j-bin-1.6.7.zip (the binary)
wss4j-bin-1.6.7.zip.asc  (and its respective .asc file)


1. First, put the both target files under the same folder.

2. Disvover the ID, typing the command (GnuPG must be installed):
 gpg wss4j-bin-1.6.7.zip.asc
 or
 gpg --verify wss4j-bin-1.6.7.zip.asc

The output:
gpg: Signature made Wed 25 Jul 2012 11:25:57 AM BRT using RSA key ID 0AD53983
gpg: Can't check signature: public key not found

3. Getting the public key from a trusted source, a public well known and reliable keyserver:
 gpg --keyserver pgpkeys.mit.edu --recv-key 0AD53983

4. After importing, repeat the 3rd step.
Now it shall recognize the signature against the target file:
 gpg wss4j-bin-1.6.7.zip.asc
 or
 gpg --verify wss4j-bin-1.6.7.zip.asc

Output:
gpg: Signature made Wed 25 Jul 2012 11:25:57 AM BRT using RSA key ID 0AD53983
gpg: Good signature from "Colm O hEigeartaigh <coheigea@apache.org>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: DB45 ECD1 9B97 514F 7271  05AE 67BF 80B1 0AD5 3983

Notice that the last 8 digits from the fingerprint shall be equal to the key ID.


5. Getting the fingerprint to validade the public key:
 gpg --fingerprint 0AD53983

Output:
pub   2048R/0AD53983 2011-02-10
Key fingerprint = DB45 ECD1 9B97 514F 7271  05AE 67BF 80B1 0AD5 3983
uid                  Colm O hEigeartaigh <coheigea@apache.org>
sub   2048R/1C6209E9 2011-02-10



6. Checking if the public key really exists.

Above (3rd step), we got the public key from MIT.

So, checking using another trusted source to confirm, we search by "coheigea" at RedIris .

The result returned:


The ID 0AD53983 was also found on another reliable public keyserver.
Remember that a keyring or keyserver may be tampered also, but exactly the two ones at the same time... it's something quite remote.





7. Who is coheigea@apache.org?

We can not call him on the phone or cell.
Imagine, zillions of people doing that... No way!
So, that's when networking comes in.


Our first attempt, following the Apache's documentation is to point to the Apache's web of trust at
 http://people.apache.org/~henkp/trust/apache.html


He was not found there and probably is not up to date or something else, but after a fast search on web, he was found on twitter  and belongs to the Apache community.



8. Does somebody else know and endorse Colm O hEigeartaigh?

Let's verify, issuing:
 gpg wss4j-bin-1.6.7.zip.asc
 or
 gpg --verify wss4j-bin-1.6.7.zip.asc

Output:
gpg: Signature made Wed 25 Jul 2012 11:25:57 AM BRT using RSA key ID 0AD53983
gpg: Good signature from "Colm O hEigeartaigh "
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: DB45 ECD1 9B97 514F 7271  05AE 67BF 80B1 0AD5 3983

It's signed by itself.
To discover more details about that signature, do:
 gpg --list-sigs 0AD53983

Output:
pub   2048R/0AD53983 2011-02-10
uid                  Colm O hEigeartaigh
sig          DEDEAB92 2012-02-06  [User ID not found]
sig 3        0AD53983 2011-02-10  Colm O hEigeartaigh
sub   2048R/1C6209E9 2011-02-10
sig          0AD53983 2011-02-10  Colm O hEigeartaigh

On the output (yellow), we see that it is signed by 0AD53983.
Who is 0AD53983?

To answer, we do:
 gpg --keyserver pgpkeys.mit.edu --recv-key DEDEAB92

Output:
gpg: requesting key DEDEAB92 from hkp server pgpkeys.mit.edu
gpg: key DEDEAB92: public key "Sergey Beryozkin (Release Management) " imported
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   3  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 3u
gpg: next trustdb check due at 2012-12-02
gpg: Total number processed: 1
gpg:               imported: 1


9. Who is sberyozkin@gmail.com?                                                                        
Again, the same problem, we can not get a direct contact, but we can check the informations to discover if they match and are coherent.

Searching for "sberyozkin" we find many sources including his twitter, noticing that he also works on Apache's community and etc.


As we see, details match...

So, this is web of trust, not directly endorsed but endorsed indirectly by networking using social media and other sources.

Conclusion:                                                                                                           
His ID is found on two public trusted sources, and he's a well known and active member of Apache's community working on the respective subject and also endorsed by somebody else "on the field".

Enough, done.

If the target were not well known, certainly it would be necessary to extend the networking survey, to grab enough information to create a context that could give us some kind of security.


Important Considerations


1. Alternatives and Additional Tips

Many sites have a section on the download page that shows how to test integrity and offer a key list of developers.

Very handy because you enrich your keyring faster.
More practical, instead of importing one by one when you need, as done above by example.

As referred on the beginning, Apache offers the keys on the download pages, for instance go to apache geronimo (the application server).

You find there a reference to a KEYS file containing such keys.


2. Good practices

From Apache's tutorial, we get:

...
Attackers can easily create new keys similar to yours with identical user IDs and comments.
Such a public key may be introduced to your keyring when you download keys from a public keyserver or as part of an import.

...
Trusting that an import contains only the owner's public key is not recommended.
The import may contain additional public keys (either intentionally or not).
So, when using an import, always verify the key ID of interest from another source.

...
                                                                                   

In practice, in most of the cases, it is not possible to get in touch with the owner.
So, consider some good and important additional security practices:

1. Keep control of the keyring's number of registries.
Check before and after the import.

2. After an import, always check it, otherwise your keyring will loose confidence.

3. Create a backup after an import operation and periodically.
Check http://www.apache.org/dev/openpgp.html#backup-private


To count the number of registries of your keyring you can use a script like this :

#!/bin/sh
# last update: 11/08/2012 11:34:53 AM
# name: gpgcounter
#
# target: returns the number of registries on a GnuPG keyring.
#
#IMPORTANT NOTE:
#On the GnuPG's man page, there is a note:
#  Avoid  using the output of this command in scripts or other programs
#  as it is likely to change as GnuPG  changes.
#
# So, you shall test the script with your version before using it.
#
# syntax:
#
#   gpgcounter
# set here the GnuPG version used for creation or test
GPGVER="1.4.9"

pubs=$(gpg --list-keys | grep '^pub' | uniq -c | awk '{sum += $1} END {print sum}')
uids=$(gpg --list-keys | grep '^uid' | uniq -c | awk '{sum += $1} END {print sum}')
subs=$(gpg --list-keys | grep '^sub' | uniq -c | awk '{sum += $1} END {print sum}')
gpgver=$( gpg --version | grep ^gpg | awk '{print $3}')

if ! [ "$gpgver" = "$GPGVER" ] ; then
    echo ""
    echo "**************************************************************************"
    echo "[WARN]: this script was tested with gpg v.$GPGVER."
    echo "  The current GnuPG version (v.$gpgver) differs from v.$GPGVER  (See: gpg --version)"
    echo "     Check the following command in order to confirm its validity:"
    echo "       gpg --list-keys"
    echo "  It shall return an output formatted like the following example:    "
    echo "       pub   4096R/2E63F262 2012-07-13"
    echo "       uid          John Xiao (CODE SIGHING KEY) "
    echo "       sub   4096R/64F9AF14 2012-07-13"
    echo ""
    echo " If the output format is different from the example, the script must be altered to reflect the new changes."
    echo ""
else
    echo "[INFO]: gpgcounter totals (pub, uid, sub): $pubs, $uids, $subs at $(date +%y%m%d_%H%M%S) by $USER for gpg v.$GPGVER"
fi  


If *nix environment, create the file gpgcounter.sh copying the content above, then do:
chmod 755 gpgcounter.sh
./gpgcounter.sh

The little script will return something like this:
 [INFO]: gpgcounter totals (pub, uid, sub): 6, 7, 5 at 121106_174037 by alsdias  for gpg v.1.4.9                                   

Save the information to an encrypted control file somewhere else.
If your keyring is tampered, certainly you'll have a better chance to discover it.

NOTE:                                                                                                  

On the GnuPG's man page, there is a note:
   Avoid  using the output of this command in scripts or other programs 
   as it is likely to change as GnuPG  changes.

So, the script also tests your current version.
If the current version differs, it returns a warning.
It also has a note for which version it was created, echoing it into the statistics returned.
That way, the script checks and alerts the user about the version that it was created or tested for.



Conclusion                                                                                                              


Security comes from the basis.
Import is a key point.
Think about it.


Additional sources:
Apache's tutorial
apache geronimo download site containing instructions

Thursday, November 1, 2012

gpg - Not enough random bytes available - Best Solution



After issuing the command
  gpg --gen-key

trying to generate a key pair using gpg I got the message:


Not enough random bytes available.  Please do some other work to give
the OS a chance to collect more entropy! (Need 280 more bytes)


BEST SOLUTION

After some search on web, I got different procedures, and I began testing them.

The one that really worked successfully was that using rng-tools.
A tutorial to set up rng-tools can be found at:
http://www.howtoforge.com/helping-the-random-number-generator-to-gain-enough-entropy-with-rng-tools-debian-lenny

besides being the most practical solution.
The gpg command started working without failures, being stable.

I've create a summary with additional information for the alternative solutions which are described below just in case being useful someway.

Unfortunately, the alternative solutions using  ls / -R  or  find / > /dev/null  and the  --no-use-agent  flag were not always successful.
I've got some success but also failures, using the same environment and procedures. So far, for professional usage I've discarded, but they can be a valuable attempt if you have no rights to install packages on the target environment and need a temporary solution during an emergency.



ALTERNATIVE SOLUTIONS

Go to terminal and check your entropy:
  watch cat /proc/sys/kernel/random/entropy_avail

You're gonna get a real time feedback as an entropy number.
The biggest, the best.
Lower system activity, lower entropy number.

GPG requires high entropy.


Go to a second shell and start the following command:
  ls / -R


Let it running.

Return to the prior terminal - the entropy shall be increasing.

Still let ls command running.


Go to a third terminal to generate the key pair using this command:
   gpg --gen-key --no-use-agent

That's it. Done.
But...


Why the --no-use-agent flag?

Checking man (man gpg), you see:

       --no-use-agent
              Try to use the GnuPG-Agent.  With this option, GnuPG first tries
              to connect to the agent before it asks for a  passphrase.  --no-
              use-agent disables this option.


       --gpg-agent-info
              Override    the    value    of    the    environment    variable
              'GPG_AGENT_INFO'’. This is only used when --use-agent  has  been
              given.   Given  that this option is not anymore used by gpg2, it
              should be avoided if possible.


Probably this issue is already fixed in newer versions.



If you need to generate more entropy, try this:

- using find command by other way:

http://michaelheap.com/not-enough-random-bytes-available-gpg-signing/
- using stress tool from:
http://packages.debian.org/squeeze/stress
  suggested by:
http://stackoverflow.com/questions/12257653/pgp-not-enough-random-bytes-available-please-do-some-other-work-to-give-the-o



If  this procedure still fails, there is also, an interesting procedure using rng-tools at:

https://bugs.launchpad.net/ubuntu/+source/gnupg/+bug/706011


To check you gpg version:
  gpg --version


The information compiled here was based on several posts, among them:

http://avinashpillai.blogspot.com/2011/12/gpg-keygen-not-enough-random-bytes.html
http://stackoverflow.com/questions/11708334/pgp-asymmetric-not-enough-random-bytes-available-please-do-some-other-work-to
http://stackoverflow.com/questions/12257653/pgp-not-enough-random-bytes-available-please-do-some-other-work-to-give-the-o
http://michaelheap.com/not-enough-random-bytes-available-gpg-signing/
https://bugs.launchpad.net/ubuntu/+source/gnupg/+bug/706011

Friday, October 26, 2012

Colocou na Internet, já é e sem "undo".




Uma amiga nossa postou isso no FB:


     IMPORTANTE...
     A todos meus contatos, PEÇO UM FAVOR: com as mudanças do Facebook,
agora todos ficam sabendo das nossas coisas, gente que nem está nos
nossos contatos, só porque um contato faz um "comentário" ou "curte"
algo nosso. Gentileza observar: aqui mesmo, acima a esquerda, posicione
o mouse sobre a minha foto , o meu avatar, (sem clicar). Espere até
aparecer uma janela e posicione o mouse sobre o icone "Amigos" (também
sem clicar), depois vá até "Configurações" e aí sim clique. Vai aparecer
uma lista: clique em "Comentários e Curtir" desmarcando essa opção.
Assim minhas atividades ficarão restritas aos meus amigos e familiares,
não se tornando domínio público. Se quiser copiar e colar no seu mural,
irá assegurar a sua privacidade.
     Obrigada a todos. (UMA BOA IDEIA)


é isso mesmo?
-----------------------------------

Certamente, os relacionamentos não são alterados na base de dados em função da configuração.

A configuração é um ajuste pessoal, que filtra a visualização da informação que você deseja ver, e que certamente não interfere na máquina de busca e associações das medias sociais.

Desativar uma opção pode garantir uma personalização da visualização, apenas.
Por que?
Imagine que a configuração pessoal afetasse o banco de dados, então uma vez desabilitada, não poderia ser novamente ativada, sem possível perda de informações.

Imagine que A é amigo de B, e B amigo de C.
Todos deixaram inicialmente suas configurações habilitas.
Oras, se B ao desabilitar alterasse a base de dados, então exigiria a sincronização desses dados entre A, B e C.
Certamente desapareceriam das telas de A e C informações, misteriosamente, por decorrência da ação de B.
Muitos casos ficariam estranhos.
Isso examinado nesse caso trivial é muito simples, mas a replicação recursiva por toda a malha de associações do banco de dados seria imprevisível e extremamente dispendiosa.
E quando falamos de banco de dados de medias sociais, é algo gigantesco, que qualquer DBA "começa a suar frio" só de pensar em perder a consistência do banco.

Portanto, é que nem cofrinho do tipo "porquinho inquebrável".
Colocou a moedinha ali, nunca mais!

Outro fator "chave" - o interesse econômico.
Por trás disso, existe o interesse comercial, porque a massa de dados é vendida (ou arrendada, alugada, seja lá como for... ) para operações de data warehousing, que extraem perfis e estatística do tipo que alimentam os sites, além da indústria de marketing, e toda a sorte de especulação de comportamento, rastreamento e tendências sociais.

É daí que vem o subsídio sustenta o caráter "free" da rede.


-----
Social Media Tracking
Rastreamento em Media Social

Estendendo o texto acima, sobre a possibilidade de um "undo" em medias sociais, ou seja desfazer algo enviado, segue abaixo, uma pesquisa realizada (embora já o saibamos de ouvir falar) sobre as informações colhidas por aplicativos "facebook" (e cia).


 

 Observando-a, poderemos entender melhor a questão.

A situação é ainda mais "complicada" porque o rastreamento é realizado por diversas alternativas.
A coleta de dados provenientes de fontes diversas é consolidada em pesquisas.

Havendo várias fontes alternativas, mesmo que um dado pudesse ser eventualmente apagado ou modificado, poderia ser reescrito.
Por que?
É o efeito colateral da replicação da informação.
Através dela e mediante a consolidação de dados, pode-se obter uma taxa de confiabilidade do dado que foi inserido ou a ainda aponta-se a diversidade de alternativas para aquele usuário.
Por exemplo, um mesmo usuário com vários e-mails ou endereços díspares, incoerentes, etc.

A replicação de fontes promove o enriquecimento multidimensional do data warehouse.
Ou seja, gradativamente, o conjunto de dados é enriquecido com novas informações que permitam gerar um novo contexto e que favoreçam a criação de uma dimensão extra no banco de dados.
Cada dimensão pode ser uma aspecto da sua vida...

Conclusão, até mesmo a singela "mentira" como forma de proteção pessoal fica cada vez mais frágil ou inócua.

Sugestões para reduzir sua exposição, lembre-se:

1. Qualquer via Internet é pública e sem volta (sem "undo").
    Pense muito bem antes de digitar.

2. Adote como regra não trafegar informações pessoais.
    Fique restrito àquelas exclusivamente necessárias ou já públicas de fato (seu e-mail, por exemplo).

3. O dado irrelevante de hoje, ou até mesmo inocente, pode ser muito relevante amanhã.
    Porque um novo contexto passa a fazer sentido para algo que não o tinha isoladamente.

4. Qualquer informação pode adquirir um contexto à medida que é somada a outra.
    Além das análises dimensionais de data warehouses temos que lembrar os recursos de análise oferecidos pela inteligência artificial (AI).
    Por exemplo, podemos realizar classificações utilizando redes kohonem, que podem até mesmo classificar eletrocardiogramas (ECG).
    Por curiosidade, veja o site:
   
http://www.pee.ufrj.br/teses/?Resumo=2000034001

5. Tudo que é de graça tem preço caro embutido de alguma forma e não declarado explicitamente, que talvez você não desejasse arcar.

6. Evite instalação de softwares gratuitos.
    Grande parte dos softwares que prestam serviços simples de áudio, vídeo, comunicação, recursos gráficos e etc. são grandes candidatos a vetores de informação social como forma de autosustentação econômica.
    Hardware hoje é barato.
    Se precisar usar software não confiável, eleja uma máquina só para isso.
    Reserve outra máquina para uso pessoal e privado apenas com o que for considerado seguro e necessário.

7. Utilize e pesquise ferramentas de segurança pagas e dê preferência a software pago de fonte segura.
    Lembre-se: nada trabalha de graça - não há milagre.

8. Criptografe o que for pessoal com entropia acima de 1024bits.
    E não mantenha a chave no mesmo ambiente...

eclipse: java: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder" or Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder

  >PROBLEM Using Eclipse, you try to run a simple logging test using "org.slf4j.Logger" like the sample below: package Test; im...