/**
* Copyright Plugtree LLC
*
* 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.
*/
package com.plugtree.solrmeter.controller.statisticsParser.castor;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.XMLContext;
import org.xml.sax.InputSource;
import com.plugtree.solrmeter.controller.StatisticDescriptor;
import com.plugtree.solrmeter.controller.StatisticType;
import com.plugtree.solrmeter.controller.statisticsParser.ParserException;
import com.plugtree.solrmeter.controller.statisticsParser.StatisticsParser;
import com.plugtree.solrmeter.model.FileUtils;
import com.plugtree.solrmeter.model.OptimizeStatistic;
import com.plugtree.solrmeter.model.QueryStatistic;
import com.plugtree.solrmeter.model.UpdateStatistic;
import com.plugtree.solrmeter.view.StatisticPanel;
/**
* Castor Implementation for StatisticsParser
* @author tflobbe
*
*/
public class StatisticsParserCastorImpl implements StatisticsParser {
@Override
public List<StatisticDescriptor> getStatisticDescriptors(String filePath)
throws ParserException {
try {
Mapping mapping = new Mapping();
mapping.loadMapping(FileUtils.findFileAsResource("StatisticDescriptorMapping.xml"));
XMLContext context = new XMLContext();
context.addMapping(mapping);
InputSource source = new InputSource(FileUtils.findFileAsStream(filePath));
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setClass(StatisticList.class);
StatisticList list = (StatisticList)unmarshaller.unmarshal(source);
validate(list.getDescriptors());
return list.getDescriptors();
} catch (Exception e) {
ParserException parserException = new ParserException("Exception parsing statistic descriptor files", e);
Logger.getLogger(this.getClass()).error(parserException.getMessage(), parserException);
throw parserException;
}
}
/**
* Validates the generated descriptors
* @param descriptors
* @throws ParserException
*/
private void validate(List<StatisticDescriptor> descriptors) throws ParserException {
this.validateDuplicatedNames(descriptors);
this.validateNoView(descriptors);
this.validateTypes(descriptors);
this.validateModelClass(descriptors);
this.validateVewClass(descriptors);
}
/**
* Validate that when a statistic has a view, it's view class extends StatisticPanel
* @param descriptors
* @throws ParserException
*/
private void validateVewClass(List<StatisticDescriptor> descriptors) throws ParserException {
for(StatisticDescriptor descriptor:descriptors) {
if(descriptor.isHasView()) {
if(!StatisticPanel.class.isAssignableFrom(descriptor.getViewClass())) {
throw new ParserException("Error on descriptor of statistic" + descriptor.getName() + ". " +
descriptor.getViewClass() + " can't be used as a View Class becouse is not a StatisticPanel");
}
}
}
}
/**
* Validate that when a statistic has a type, it's model class implements the necesary interface
* @param descriptors
* @throws ParserException
*/
private void validateModelClass(List<StatisticDescriptor> descriptors) throws ParserException {
for(StatisticDescriptor descriptor:descriptors) {
if(descriptor.getTypes().contains(StatisticType.OPTIMIZE)) {
validateInterface(descriptor.getModelClass(), OptimizeStatistic.class);
}
if(descriptor.getTypes().contains(StatisticType.QUERY)) {
validateInterface(descriptor.getModelClass(), QueryStatistic.class);
}
if(descriptor.getTypes().contains(StatisticType.UPDATE)) {
validateInterface(descriptor.getModelClass(), UpdateStatistic.class);
}
}
}
/**
* Validates that the model class implements the statisticInterface
* @param modelClass
* @param statisticInterface
* @throws ParserException
*/
private void validateInterface(Class<?> modelClass,
Class<?> statisticInterface) throws ParserException {
if(!statisticInterface.isAssignableFrom(modelClass)) {
throw new ParserException("The class " + modelClass + " shoul implement the interface " + statisticInterface + " or the related type has to be removed.");
}
}
/**
* Validate that the types are valid and are not repeated
* @param descriptors
* @throws ParserException
*/
private void validateTypes(List<StatisticDescriptor> descriptors) throws ParserException {
for(StatisticDescriptor descriptor:descriptors) {
if(descriptor.getTypes().size() == 0) {
throw new ParserException("There has to be at least one type for statistic " + descriptor.getName());
}
int index = 0;
for(StatisticType type:descriptor.getTypes()) {
if(descriptor.getTypes().lastIndexOf(type) != index) {
throw new ParserException("The statistic type " + type.name() + " of statistic " + descriptor.getName() + " is repeated.");
}
index++;
}
}
}
/**
* Validate that all statistics that has a view (have the hasView attribute set to true)
* have a viewClass asociated
* @param descriptors
* @throws ParserException
*/
private void validateNoView(List<StatisticDescriptor> descriptors) throws ParserException {
for(StatisticDescriptor descriptor:descriptors) {
if(descriptor.isHasView() && descriptor.getViewClass() == null) {
throw new ParserException("The descriptor for name " + descriptor.getName() + " should have a view class or have the 'hasView' attribute setted to false");
}
if(!descriptor.isHasView() && descriptor.getViewClass() != null) {
Logger.getLogger(this.getClass()).warn("The descriptor " + descriptor.getName() + " has a view class but it's 'hasView' attribute is set to false");
}
}
}
/**
* Validate that there are no repeated names on the descriptors
* @param descriptors
* @throws ParserException
*/
private void validateDuplicatedNames(List<StatisticDescriptor> descriptors) throws ParserException {
Set<String> existingNames = new HashSet<String>();
for(StatisticDescriptor descriptor:descriptors) {
if(existingNames.contains(descriptor.getName())) {
throw new ParserException("The name " + descriptor.getName() + " is duplicated. Names must be unique");
}else {
existingNames.add(descriptor.getName());
}
}
}
}