/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. */ package org.olat.course.statistic.export; import static java.util.Locale.ENGLISH; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.logging.activity.LoggingObject; import org.olat.core.util.Encoder; import org.olat.core.util.StringHelper; /** * Converter class to take a LoggingObject and convert it into a (csv) line * <p> * Primarily a helper class for the ICourseLogExporter implementations. * <P> * Initial Date: 06.01.2010 <br> * @author Stefan */ public class LogLineConverter { /** the logging object used in this class **/ private static final OLog log_ = Tracing.createLoggerFor(LogLineConverter.class); /** spring property defining all properties - including the order in which they will be exported **/ private List<String> orderedExportedProperties = new ArrayList<String>(); /** spring property defining all properties which should be anonymized - they must also be in orderedExportedProperties **/ private Set<String> anonymizedProperties = new HashSet<String>(); /** internal property which contains (javax.bean) PropertyDescriptors of each of the above property - * given the properties are available */ private List<PropertyDescriptor> orderedExportedPropertyDescriptors = new ArrayList<PropertyDescriptor>(); /** * spring property setter for orderedExportedProperties - which is the list of all properties to be extracted * from the LoggingObject and exported in the csv format * @param orderedExportedProperties */ public void setOrderedExportedProperties(List<String> orderedExportedProperties) { this.orderedExportedProperties = orderedExportedProperties; initPropertyDescriptor(); } /** * spring property setter for anonymizedProperties - all of these must also be in the orderedExportedProperties list */ public void setAnonymizedProperties(Set<String> anonymizedProperties) { this.anonymizedProperties = anonymizedProperties; } /** * Returns a String which capitalizes the first letter of the string. * (c) from java.beans.NameGenerator (which unfortunatelly is not a public class) */ public static String capitalize(String name) { if (name == null || name.length() == 0) { return name; } return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1); } /** * Initialize the (java.bean) PropertyDescriptors for the properties */ private void initPropertyDescriptor() { for (Iterator<String> it = orderedExportedProperties.iterator(); it.hasNext();) { String propertyName = it.next(); try { // we're using this specialized constructor since we want to allow properties that are read-only (such as creationDate). // with the simpler constructor (String,Class) that would result in an Exception. // also note that we're using "is"+propertyName rather than get - that's the way the PropertyDescriptor itself // does it in the constructor (String,Class) - resulting in a lookup of an is Method first and then the get Method // this seems to be the correct standard here. PropertyDescriptor pd = new PropertyDescriptor(propertyName, LoggingObject.class, "is" + capitalize(propertyName), null); orderedExportedPropertyDescriptors.add(pd); } catch (IntrospectionException e) { log_.error("initPropertyDescriptor: Could not retrieve property "+propertyName+" from LoggingObject, configuration error?", e); } } } /** * Returns the CSV Header line containing all property names in the exact same way as in the config file - * excluding those properties which could not be retrieved, i.e. for which no PropertyDescriptor could be created * @return the CSV Header line containing all property names in the exact same way as in the config file - * excluding those properties which could not be retrieved, i.e. for which no PropertyDescriptor could be created */ public String getCSVHeader() { List<String> propertyNames = new ArrayList<String>(); for (Iterator<PropertyDescriptor> it = orderedExportedPropertyDescriptors.iterator(); it.hasNext();) { PropertyDescriptor pd = it.next(); propertyNames.add(pd.getName()); } return StringHelper.formatAsCSVString(propertyNames); } /** * Returns a CSV line for the given LoggingObject - containing all properties in the exact same way as in the * config file - excluding those which could not be retrieved, i.e. for which no PropertyDescriptor could be * created * @param loggingObject the LoggingObject for which a CSV line should be created * @return the CSV line representing the given LoggingObject */ public String getCSVRow(LoggingObject loggingObject, boolean anonymize, Long resourceableId) { List<String> loggingObjectList = new ArrayList<String>(); for (Iterator<PropertyDescriptor> it = orderedExportedPropertyDescriptors.iterator(); it.hasNext();) { PropertyDescriptor pd = it.next(); String strValue = ""; try { Object value = pd.getReadMethod().invoke(loggingObject, (Object[])null); if (value!=null) { strValue = String.valueOf(value); } if (anonymize && anonymizedProperties.contains(pd.getName())) { // do anonymization strValue = makeAnonymous(String.valueOf(value), resourceableId); } } catch (IllegalArgumentException e) { // nothing to do } catch (IllegalAccessException e) { // nothing to do } catch (InvocationTargetException e) { // nothing to do } loggingObjectList.add(strValue); } return StringHelper.formatAsCSVString(loggingObjectList); } /** * encode a string and course resourcable id with MD5 * @param s * @param courseResId * @return */ private String makeAnonymous(String s, Long courseResId) { String encodeValue = s + "-" + Long.toString(courseResId); // encode with MD5 return Encoder.md5hash(encodeValue); } }