001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.devtools.pdle;
017
018import org.apache.commons.beanutils.PropertyUtils;
019import org.apache.log4j.Logger;
020import org.apache.ojb.broker.accesslayer.conversions.FieldConversionDefaultImpl;
021import org.apache.ojb.broker.metadata.ClassDescriptor;
022import org.kuali.rice.core.api.CoreApiServiceLocator;
023import org.kuali.rice.core.api.encryption.EncryptionService;
024import org.kuali.rice.core.framework.persistence.ojb.conversion.OjbKualiEncryptDecryptFieldConversion;
025import org.kuali.rice.krad.bo.PersistableBusinessObject;
026import org.kuali.rice.krad.exception.ClassNotPersistableException;
027import org.kuali.rice.krad.service.BusinessObjectService;
028import org.kuali.rice.krad.service.impl.PersistenceServiceImplBase;
029
030import java.util.Collections;
031import java.util.Set;
032
033import java.util.ArrayList;
034import java.util.HashMap;
035import java.util.List;
036import java.util.Map;
037import java.util.Set;
038
039public class PostDataLoadEncryptionServiceImpl extends PersistenceServiceImplBase implements PostDataLoadEncryptionService {
040    protected Logger LOG = Logger.getLogger(PostDataLoadEncryptionServiceImpl.class);
041
042    private BusinessObjectService businessObjectService;
043    private EncryptionService encryptionService;
044    private PostDataLoadEncryptionDao postDataLoadEncryptionDao;
045
046    @Override
047    public void checkArguments(Class<? extends PersistableBusinessObject> businessObjectClass, Set<String> attributeNames) {
048        checkArguments(businessObjectClass, attributeNames, true);
049    }
050
051    @Override
052    public void checkArguments(Class<? extends PersistableBusinessObject> businessObjectClass, Set<String> attributeNames, boolean checkOjbEncryptConfig) {
053        if ((businessObjectClass == null) || (attributeNames == null)) {
054            throw new IllegalArgumentException(
055                    "PostDataLoadEncryptionServiceImpl.encrypt does not allow a null business object Class or attributeNames Set");
056        }
057        final ClassDescriptor classDescriptor;
058        try {
059            classDescriptor = getClassDescriptor(businessObjectClass);
060        } catch (ClassNotPersistableException e) {
061            throw new IllegalArgumentException(
062                    "PostDataLoadEncryptionServiceImpl.encrypt does not handle business object classes that do not have a corresponding ClassDescriptor defined in the OJB repository",
063                    e);
064        }
065        for (String attributeName : attributeNames) {
066            if (classDescriptor.getFieldDescriptorByName(attributeName) == null) {
067                throw new IllegalArgumentException(
068                        new StringBuffer("Attribute ")
069                                .append(attributeName)
070                                .append(
071                                        " specified to PostDataLoadEncryptionServiceImpl.encrypt is not in the OJB repository ClassDescriptor for Class ")
072                                .append(businessObjectClass).toString());
073            }
074            if (checkOjbEncryptConfig && !(classDescriptor.getFieldDescriptorByName(attributeName).getFieldConversion() instanceof OjbKualiEncryptDecryptFieldConversion)) {
075                throw new IllegalArgumentException(
076                        new StringBuffer("Attribute ")
077                                .append(attributeName)
078                                .append(" of business object Class ")
079                                .append(businessObjectClass)
080                                .append(
081                                        " specified to PostDataLoadEncryptionServiceImpl.encrypt is not configured for encryption in the OJB repository")
082                                .toString());
083            }
084        }
085    }
086
087    @Override
088    public void createBackupTable(Class<? extends PersistableBusinessObject> businessObjectClass) {
089        postDataLoadEncryptionDao.createBackupTable(getClassDescriptor(businessObjectClass).getFullTableName());
090    }
091
092    @Override
093    public void prepClassDescriptor(Class<? extends PersistableBusinessObject> businessObjectClass, Set<String> attributeNames) {
094        ClassDescriptor classDescriptor = getClassDescriptor(businessObjectClass);
095        for (String attributeName : attributeNames) {
096            classDescriptor.getFieldDescriptorByName(attributeName).setFieldConversionClassName(
097                    FieldConversionDefaultImpl.class.getName());
098        }
099    }
100
101    @Override
102    public void truncateTable(Class<? extends PersistableBusinessObject> businessObjectClass) {
103        postDataLoadEncryptionDao.truncateTable(getClassDescriptor(businessObjectClass).getFullTableName());
104    }
105
106    @Override
107    public void encrypt(PersistableBusinessObject businessObject, Set<String> attributeNames) {
108        for (String attributeName : attributeNames) {
109            try {
110            if(CoreApiServiceLocator.getEncryptionService().isEnabled()) {
111                        PropertyUtils.setProperty(businessObject, attributeName, encryptionService.encrypt(PropertyUtils
112                                .getProperty(businessObject, attributeName)));
113            }
114            } catch (Exception e) {
115                throw new RuntimeException(new StringBuffer(
116                        "PostDataLoadEncryptionServiceImpl caught exception while attempting to encrypt attribute ").append(
117                        attributeName).append(" of Class ").append(businessObject.getClass()).toString(), e);
118            }
119        }
120        businessObjectService.save(businessObject);
121    }
122
123    @Override
124    public void restoreClassDescriptor(Class<? extends PersistableBusinessObject> businessObjectClass, Set<String> attributeNames) {
125        ClassDescriptor classDescriptor = getClassDescriptor(businessObjectClass);
126        for (String attributeName : attributeNames) {
127            classDescriptor.getFieldDescriptorByName(attributeName).setFieldConversionClassName(
128                    OjbKualiEncryptDecryptFieldConversion.class.getName());
129        }
130        businessObjectService.countMatching(businessObjectClass, Collections.<String, Object>emptyMap());
131    }
132
133    @Override
134    public void restoreTableFromBackup(Class<? extends PersistableBusinessObject> businessObjectClass) {
135        postDataLoadEncryptionDao.restoreTableFromBackup(getClassDescriptor(businessObjectClass).getFullTableName());
136    }
137
138    @Override
139    public void dropBackupTable(Class<? extends PersistableBusinessObject> businessObjectClass) {
140        postDataLoadEncryptionDao.dropBackupTable(getClassDescriptor(businessObjectClass).getFullTableName());
141    }
142
143    @Override
144    public boolean doesBackupTableExist(String tableName){
145        return postDataLoadEncryptionDao.doesBackupTableExist(tableName);
146    }
147    
148    @Override
149    public void createBackupTable(String tableName) {
150        postDataLoadEncryptionDao.createBackupTable(tableName);
151        postDataLoadEncryptionDao.addEncryptionIndicatorToBackupTable(tableName);
152    }
153    
154    @Override
155    public void truncateTable(String tableName) {
156        postDataLoadEncryptionDao.truncateTable(tableName);
157    }
158
159    @Override
160    public List<Map<String, String>> retrieveUnencryptedColumnValuesFromBackupTable(String tableName, final List<String> columnNames, int numberOfRowsToCommitAfter) {
161        return postDataLoadEncryptionDao.retrieveUnencryptedColumnValuesFromBackupTable(tableName, columnNames, numberOfRowsToCommitAfter);
162    }
163
164    @Override
165    public boolean performEncryption(final String tableName, final List<Map<String, String>> rowsToEncryptColumnsNameValueMap) throws Exception {
166        List<Map<String, List<String>>> rowsToEncryptColumnNameOldNewValuesMap = new ArrayList<Map<String, List<String>>>();
167        for(Map<String, String> columnsNameValueMap: rowsToEncryptColumnsNameValueMap){
168            rowsToEncryptColumnNameOldNewValuesMap.add(getColumnNamesEncryptedValues(tableName, columnsNameValueMap));
169        }
170        return postDataLoadEncryptionDao.performEncryption(tableName, rowsToEncryptColumnNameOldNewValuesMap); 
171    }
172
173    public Map<String, List<String>> getColumnNamesEncryptedValues(String tableName, final Map<String, String> columnNamesValues) {
174        List<String> oldNewValues = new ArrayList<String>();
175        String columnOldValue;
176        Map<String, List<String>> columnNameOldNewValuesMap = new HashMap<String, List<String>>();
177        for (String columnName: columnNamesValues.keySet()) {
178            try {
179                oldNewValues = new ArrayList<String>();
180                columnOldValue = columnNamesValues.get(columnName);
181                //List chosen over a java object (for old and new value) for better performance
182                oldNewValues.add(PostDataLoadEncryptionDao.UNENCRYPTED_VALUE_INDEX, columnOldValue);
183                if(CoreApiServiceLocator.getEncryptionService().isEnabled()) {
184                    oldNewValues.add(PostDataLoadEncryptionDao.ENCRYPTED_VALUE_INDEX, encryptionService.encrypt(columnOldValue));
185                }
186                columnNameOldNewValuesMap.put(columnName, oldNewValues);
187            } catch (Exception e) {
188                throw new RuntimeException(new StringBuffer(
189                "PostDataLoadEncryptionServiceImpl caught exception while attempting to encrypt Column ").append(
190                columnName).append(" of Table ").append(tableName).toString(), e);
191            }
192        }
193        return columnNameOldNewValuesMap;
194    }
195
196    @Override
197    public void restoreTableFromBackup(String tableName) {
198        postDataLoadEncryptionDao.dropEncryptionIndicatorFromBackupTable(tableName);
199        postDataLoadEncryptionDao.restoreTableFromBackup(tableName);
200    }
201
202    @Override
203    public void dropBackupTable(String tableName) {
204        postDataLoadEncryptionDao.dropBackupTable(tableName);
205    }    
206
207    public void setPostDataLoadEncryptionDao(PostDataLoadEncryptionDao postDataLoadEncryptionDao) {
208        this.postDataLoadEncryptionDao = postDataLoadEncryptionDao;
209    }
210
211    public void setEncryptionService(EncryptionService encryptionService) {
212        this.encryptionService = encryptionService;
213    }
214
215    public void setBusinessObjectService(BusinessObjectService businessObjectService) {
216        this.businessObjectService = businessObjectService;
217    }
218}