/*
* Copyright 2014-2016 the original author or authors.
*
* 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 org.liquigraph.core.io.xml;
import com.google.common.base.Joiner;
import org.liquigraph.core.model.Changelog;
import org.liquigraph.core.model.Changeset;
import org.w3c.dom.Node;
import java.util.Collection;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import static java.lang.String.format;
public final class ChangelogParser {
private static final String SEPARATOR = System.lineSeparator() + "\t";
private final ChangelogPreprocessor preprocessor;
private final Unmarshaller unmarshaller;
private final XmlSchemaValidator validator;
public ChangelogParser(XmlSchemaValidator validator, ChangelogPreprocessor preprocessor) {
this.validator = validator;
this.preprocessor = preprocessor;
try {
unmarshaller = JAXBContext.newInstance(Changelog.class).createUnmarshaller();
} catch (JAXBException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
/**
* Parses a <code>masterChangelog</code> XML file from the specified classloader,
* to a <code>Changelog</code> object.
*
* @param changelogLoader The changelog loader which loads the masterChangelog
* @param masterChangelog Filename of the master changelog
* @throws IllegalArgumentException if there is an error during the conversion
* @return A <code>Changelog</code> object that correspond to the XML file
*/
public Collection<Changeset> parse(ChangelogLoader changelogLoader, String masterChangelog) {
return parseChangelog(changelogLoader, masterChangelog).getChangesets();
}
private Changelog parseChangelog(ChangelogLoader changelogLoader, String masterChangelog) {
try {
Node document = preprocessor.preProcess(masterChangelog, changelogLoader);
Collection<String> errors = validator.validateSchema(document);
if (!errors.isEmpty()) {
throw new IllegalArgumentException(formatErrorMessage(errors));
}
Changelog changelog = (Changelog) unmarshaller.unmarshal(document);
fixUpChangesets(changelog);
return changelog;
} catch (JAXBException e) {
throw new IllegalArgumentException(format("Unable to parse changelog <%s>.", masterChangelog), e);
}
}
/*
* Ugly workaround due to the way JAXB handles setters
* The checksum invariant of changesets cannot be properly
* managed.
*/
private void fixUpChangesets(Changelog changelog) {
for (Changeset changeset : changelog.getChangesets()) {
changeset.setQueries(changeset.getQueries());
}
}
private String formatErrorMessage(Collection<String> errors) {
return SEPARATOR + Joiner.on(SEPARATOR).join(errors);
}
}