/**
* Copyright (C) 2010 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xcmis.spi.utils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.xcmis.spi.ItemsIterator;
import org.xcmis.spi.ObjectData;
import org.xcmis.spi.model.AccessControlEntry;
/**
* @author <a href="mailto:andrey.parfonov@exoplatform.com">Andrey Parfonov</a>
* @version $Id: CmisUtils.java 332 2010-03-11 17:24:56Z andrew00x $
*/
public final class CmisUtils
{
public static final Comparator<ObjectData> versionComparator = new Comparator<ObjectData>()
{
public int compare(ObjectData object1, ObjectData object2)
{
Calendar c1 = object1.getLastModificationDate();
Calendar c2 = object2.getLastModificationDate();
return c2.compareTo(c1);
}
};
public static ItemsIterator<Object> EMPTY_ITEMS_ITERATOR = new EmptyItemsIterator();
private static class EmptyItemsIterator implements ItemsIterator<Object>
{
public int size()
{
return 0;
}
public void skip(int skip) throws NoSuchElementException
{
throw new NoSuchElementException("skip");
}
public boolean hasNext()
{
return false;
}
public Object next()
{
throw new NoSuchElementException("next");
}
public void remove()
{
throw new UnsupportedOperationException();
}
}
public static <T> ItemsIterator<T> emptyItemsIterator()
{
return (ItemsIterator<T>)EMPTY_ITEMS_ITERATOR;
}
public static List<AccessControlEntry> createAclFromPermissionMap(Map<String, Set<String>> permissions)
{
List<AccessControlEntry> acl = new ArrayList<AccessControlEntry>();
if (permissions != null)
{
for (Map.Entry<String, Set<String>> e : permissions.entrySet())
{
AccessControlEntry ace = new AccessControlEntry(e.getKey(), e.getValue());
acl.add(ace);
}
}
return acl;
}
public static List<AccessControlEntry> mergeACLs(List<AccessControlEntry> existedAcl,
List<AccessControlEntry> addAcl, List<AccessControlEntry> removeAcl)
{
Map<String, Set<String>> cache = new HashMap<String, Set<String>>();
addAclToPermissionMap(cache, existedAcl);
addAclToPermissionMap(cache, addAcl);
removeAclFromPermissionMap(cache, removeAcl);
return createAclFromPermissionMap(cache);
}
public static void addAclToPermissionMap(Map<String, Set<String>> map, List<AccessControlEntry> acl)
{
if (acl != null)
{
for (AccessControlEntry ace : acl)
{
String principal = ace.getPrincipal();
if (principal == null)
{
continue;
}
Set<String> permissions = map.get(principal);
if (permissions == null)
{
permissions = new HashSet<String>();
map.put(principal, permissions);
}
permissions.addAll(ace.getPermissions());
}
}
}
public static void removeAclFromPermissionMap(Map<String, Set<String>> map, List<AccessControlEntry> acl)
{
if (acl != null)
{
for (AccessControlEntry ace : acl)
{
String principal = ace.getPrincipal();
if (principal == null)
{
continue;
}
Set<String> permissions = map.get(principal);
if (permissions != null)
{
permissions.removeAll(ace.getPermissions());
if (permissions.size() == 0)
{
map.remove(principal);
}
}
}
}
}
// ----- Dates ------
/** The z-format pattern. */
private static final Pattern Z_FORMAT =
Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})[Tt](\\d{2}):(\\d{2}):(\\d{2})(\\.(\\d{1,3}))?[zZ]");
/** The td-format pattern. */
private static final Pattern TD_FORMAT =
Pattern
.compile("(\\d{4})-(\\d{2})-(\\d{2})[Tt](\\d{2}):(\\d{2}):(\\d{2})(\\.(\\d{1,3}))?([+-])((\\d{2}):(\\d{2}))");
/** The ISO 8601 date format */
public static final DateFormat ISO_8601_DATE_TIME = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ");
/**
* Get XMLGregorianCalendar that is based on Calendar.
*
* @param calendar source Calendar
* @return XMLGregorianCalendar
*/
public static XMLGregorianCalendar fromCalendar(Calendar calendar)
{
XMLGregorianCalendar xmlCalendar;
try
{
xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar();
}
catch (DatatypeConfigurationException e)
{
String msg = "Unable get XMLGregorianCalendar.";
throw new RuntimeException(msg, e);
}
xmlCalendar.setYear(calendar.get(Calendar.YEAR));
xmlCalendar.setMonth(calendar.get(Calendar.MONTH) + 1);
xmlCalendar.setDay(calendar.get(Calendar.DAY_OF_MONTH));
int zoneOffsetInMinutes = (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) / (60*1000);
xmlCalendar.setTimezone(zoneOffsetInMinutes);
xmlCalendar.setTime(calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar
.get(Calendar.SECOND), calendar.get(Calendar.MILLISECOND));
return xmlCalendar;
}
/**
* Convert calendar to ISO8601 string representation.
*
* @param c the Calendar
* @return the ISO8601 string
*/
public static String convertToString(Calendar c)
{
// Can't use SimpleDateFormat here, because can't setTimeZone for it with ZONE_OFFSET in int.
int zoneOffsetInMinutes = (c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET)) / (60*1000);
String signOffset = zoneOffsetInMinutes < 0 ? "-" : "+";
zoneOffsetInMinutes = zoneOffsetInMinutes < 0 ? -zoneOffsetInMinutes : zoneOffsetInMinutes;
int hoursOffset = zoneOffsetInMinutes / 60;
int minutesOffset = zoneOffsetInMinutes % 60;
String result = String.format("%04d-%02d-%02dT%02d:%02d:%02d.%03d" + signOffset + "%02d:%02d", c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1,
c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), c.get(Calendar.SECOND),
c.get(Calendar.MILLISECOND), hoursOffset, minutesOffset);
return result;
}
/**
* Parses the calendar.
*
* @param date the date
* @return the calendar
*/
public static Calendar parseCalendar(String date)
{
Matcher m = Z_FORMAT.matcher(date);
if (m.matches())
{
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
c.set(Calendar.YEAR, Integer.parseInt(m.group(1)));
c.set(Calendar.MONTH, Integer.parseInt(m.group(2)) - 1);
c.set(Calendar.DATE, Integer.parseInt(m.group(3)));
c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(4)));
c.set(Calendar.MINUTE, Integer.parseInt(m.group(5)));
c.set(Calendar.SECOND, Integer.parseInt(m.group(6)));
c.set(Calendar.MILLISECOND, m.group(7) == null ? 0 : Integer.parseInt(m.group(8)));
return c;
}
else
{
m = TD_FORMAT.matcher(date);
if (m.matches())
{
int t = m.group(9).equals("+") ? 1 : -1;
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
c.set(Calendar.YEAR, Integer.parseInt(m.group(1)));
c.set(Calendar.MONTH, Integer.parseInt(m.group(2)) - 1);
c.set(Calendar.DATE, Integer.parseInt(m.group(3)));
c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(4)));
c.set(Calendar.MINUTE, Integer.parseInt(m.group(5)));
c.set(Calendar.SECOND, Integer.parseInt(m.group(6)));
c.set(Calendar.MILLISECOND, m.group(7) == null ? 0 : Integer.parseInt(m.group(8)));
int zoneOffset = t * (Integer.parseInt(m.group(11))*60*60*1000 + Integer.parseInt(m.group(12))*60*1000);
c.set(Calendar.ZONE_OFFSET, zoneOffset);
return c;
}
else
{
throw new IllegalArgumentException("Unsupported date format " + date);
}
}
}
/**
* Parses the xml calendar.
*
* @param date the date
* @return the xML gregorian calendar
*/
public static XMLGregorianCalendar parseXMLCalendar(String date)
{
return fromCalendar(parseCalendar(date));
}
/**
* Not instantiable.
*/
private CmisUtils()
{
}
}