/*
* (C) Copyright 2017 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Funsho David
*
*/
package org.nuxeo.ecm.core.filter;
import com.google.common.base.CharMatcher;
import org.apache.commons.lang.StringEscapeUtils;
import org.nuxeo.ecm.core.api.DataModel;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.impl.DataModelImpl;
import org.nuxeo.ecm.core.api.model.DocumentPart;
import org.nuxeo.ecm.core.api.model.Property;
import org.nuxeo.ecm.core.api.model.impl.ArrayProperty;
import org.nuxeo.ecm.core.api.model.impl.ComplexProperty;
import org.nuxeo.ecm.core.api.model.impl.ListProperty;
import org.nuxeo.ecm.core.api.model.impl.primitives.StringProperty;
import org.nuxeo.runtime.model.ComponentInstance;
import org.nuxeo.runtime.model.DefaultComponent;
import java.io.Serializable;
import java.util.List;
/**
* @since 9.1
*/
public class CharacterFilteringServiceImpl extends DefaultComponent implements CharacterFilteringService {
public static final String FILTERING_XP = "filtering";
protected CharacterFilteringServiceDescriptor desc;
protected CharMatcher charsToRemove;
@Override
public void registerContribution(Object contrib, String point, ComponentInstance contributor) {
if (FILTERING_XP.equals(point)) {
desc = (CharacterFilteringServiceDescriptor) contrib;
CharMatcher charsToPreserve = CharMatcher.anyOf("\r\n\t");
CharMatcher allButPreserved = charsToPreserve.negate();
charsToRemove = CharMatcher.JAVA_ISO_CONTROL.and(allButPreserved);
charsToRemove = charsToRemove.or(CharMatcher.INVISIBLE.and(CharMatcher.WHITESPACE.negate()));
List<String> additionalChars = desc.getDisallowedChars();
String otherCharsToRemove = "";
if (additionalChars != null && !additionalChars.isEmpty()) {
for (String c : additionalChars) {
otherCharsToRemove += StringEscapeUtils.unescapeJava(c);
}
charsToRemove = charsToRemove.or(CharMatcher.anyOf(otherCharsToRemove));
}
} else {
throw new RuntimeException("Unknown extension point: " + point);
}
}
@Override
public String filter(String value) {
return charsToRemove.removeFrom(value);
}
@Override
public void filter(DocumentModel docModel) {
if (desc.isEnabled()) {
// check only loaded datamodels to find the dirty ones
for (DataModel dm : docModel.getDataModelsCollection()) { // only loaded
if (!dm.isDirty()) {
continue;
}
DocumentPart part = ((DataModelImpl) dm).getDocumentPart();
for (Property prop : part.getChildren()) {
filterProperty(prop, docModel);
}
}
}
}
private void filterProperty(Property prop, DocumentModel docModel) {
if (!prop.isDirty()) {
return;
}
if (prop instanceof StringProperty) {
String p = (String) prop.getValue();
if (p != null && charsToRemove.matchesAnyOf(p)) {
String filteredProp = filter(p);
docModel.setPropertyValue(prop.getXPath(), filteredProp);
}
} else if (prop instanceof ArrayProperty) {
Serializable value = prop.getValue();
if (value instanceof Object[]) {
Object[] arrayProp = (Object[]) value;
boolean modified = false;
for (int i = 0; i < arrayProp.length; i++) {
if (arrayProp[i] instanceof String) {
String p = (String) arrayProp[i];
if (charsToRemove.matchesAnyOf(p)) {
arrayProp[i] = filter(p);
modified = true;
}
}
}
if (modified) {
docModel.setPropertyValue(prop.getXPath(), arrayProp);
}
}
} else if (prop instanceof ComplexProperty) {
ComplexProperty complexProp = (ComplexProperty) prop;
for (Property subProp : complexProp.getChildren()) {
filterProperty(subProp, docModel);
}
} else if (prop instanceof ListProperty) {
ListProperty listProp = (ListProperty) prop;
for (Property p : listProp) {
filterProperty(p, docModel);
}
}
}
}