diff --git a/.classpath b/.classpath new file mode 100755 index 0000000..c641afd --- /dev/null +++ b/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.project b/.project new file mode 100755 index 0000000..462a88e --- /dev/null +++ b/.project @@ -0,0 +1,35 @@ + + + spreadsheet-sandbox + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.springframework.ide.eclipse.core.springbuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.springframework.ide.eclipse.core.springnature + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100755 index 0000000..edb5db1 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,83 @@ +#Wed Aug 20 13:59:46 BST 2008 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=default +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/.settings/org.maven.ide.eclipse.prefs b/.settings/org.maven.ide.eclipse.prefs new file mode 100755 index 0000000..a2b35c4 --- /dev/null +++ b/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Sat Jun 20 14:28:55 BST 2009 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/.settings/org.springframework.ide.eclipse.beans.core.prefs b/.settings/org.springframework.ide.eclipse.beans.core.prefs new file mode 100755 index 0000000..a03e4a5 --- /dev/null +++ b/.settings/org.springframework.ide.eclipse.beans.core.prefs @@ -0,0 +1,3 @@ +#Wed May 06 08:20:22 BST 2009 +eclipse.preferences.version=1 +org.springframework.ide.eclipse.beans.core.ignoreMissingNamespaceHandler=false diff --git a/.settings/org.springframework.ide.eclipse.core.prefs b/.settings/org.springframework.ide.eclipse.core.prefs new file mode 100644 index 0000000..2f69d94 --- /dev/null +++ b/.settings/org.springframework.ide.eclipse.core.prefs @@ -0,0 +1,67 @@ +#Sun Aug 23 12:08:31 BST 2009 +eclipse.preferences.version=1 +org.springframework.ide.eclipse.core.builders.enable.aopreferencemodelbuilder=true +org.springframework.ide.eclipse.core.builders.enable.beanmetadatabuilder=true +org.springframework.ide.eclipse.core.builders.enable.osgibundleupdater=true +org.springframework.ide.eclipse.core.enable.project.preferences=false +org.springframework.ide.eclipse.core.validator.enable.com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.enable.com.springsource.sts.bestpractices.beansvalidator=true +org.springframework.ide.eclipse.core.validator.enable.com.springsource.sts.server.quickfix.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.core.springvalidator=false +org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.applicationSymbolicNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.applicationVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleActivationPolicyRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleActivatorRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleManifestVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleSymbolicNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.exportPackageRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.importRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.parsingProblemsRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.requireBundleRule-com.springsource.server.ide.manifest.core.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.AvoidDriverManagerDataSource-com.springsource.sts.bestpractices.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.ImportElementsAtTopRulee-com.springsource.sts.bestpractices.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.ParentBeanSpecifiesAbstractClassRule-com.springsource.sts.bestpractices.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.RefElementRule-com.springsource.sts.bestpractices.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.TooManyBeansInFileRule-com.springsource.sts.bestpractices.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.UnnecessaryValueElementRule-com.springsource.sts.bestpractices.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.UseBeanInheritance-com.springsource.sts.bestpractices.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.legacyxmlusage.jndiobjectfactory-com.springsource.sts.bestpractices.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importBundleVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importLibraryVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importPackageVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.requireBundleVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanAlias-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanClass-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanConstructorArgument-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinition-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinitionHolder-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanFactory-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanInitDestroyMethod-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanReference-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.methodOverride-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.parsingProblems-org.springframework.ide.eclipse.beans.core.beansvalidator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.requiredProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=false +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.core.springClasspath-org.springframework.ide.eclipse.core.springvalidator=false +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.action-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.actionstate-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attribute-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attributemapper-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.beanaction-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationaction-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationresult-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.exceptionhandler-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.import-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.inputattribute-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.mapping-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.outputattribute-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.set-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.state-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.subflowstate-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.transition-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.variable-org.springframework.ide.eclipse.webflow.core.validator=true +org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.webflowstate-org.springframework.ide.eclipse.webflow.core.validator=true diff --git a/.springBeans b/.springBeans new file mode 100644 index 0000000..67a68a3 --- /dev/null +++ b/.springBeans @@ -0,0 +1,16 @@ + + + 1 + + + + + + + src/main/resources/job-execution-context.xml + src/main/resources/simple-job-launcher-context.xml + src/test/resources/org/springframework/sample/lead/JobTests-context.xml + + + + diff --git a/lib/poi-3.5-FINAL-sources.jar b/lib/poi-3.5-FINAL-sources.jar new file mode 100644 index 0000000..ce0e179 Binary files /dev/null and b/lib/poi-3.5-FINAL-sources.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..01c5791 --- /dev/null +++ b/pom.xml @@ -0,0 +1,142 @@ + + + 4.0.0 + spreadsheet-sandbox + org.springframework.batch + spreadsheet-sandbox + 1.0.0.CI-SNAPSHOT + + 3.0.0.RC1 + + + + + true + + + + + maven-surefire-plugin + + true + + + + + + + test + + + + maven-surefire-plugin + + false + + + + + + + + + org.springframework.batch + spring-batch-core + 2.0.3.RELEASE + compile + + + org.springframework.batch + spring-batch-test + 2.0.3.RELEASE + test + + + org.apache.poi + poi + 3.5-FINAL + true + + + + org.jopendocument + jopendocument + 1.2b2 + true + + + junit + junit + 4.7 + + + log4j + log4j + 1.2.14 + + + org.aspectj + aspectjrt + test + 1.6.4 + + + org.aspectj + aspectjweaver + test + 1.6.4 + + + commons-lang + commons-lang + test + 2.4 + + + org.springframework + spring-context + ${spring.framework.version} + + + org.springframework + spring-aop + ${spring.framework.version} + + + org.springframework + spring-test + ${spring.framework.version} + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + junit:junit + + + + + + + + entelijan + http://entelijan.net/artifactory/repo + + false + + + + spring-milestones + Spring Maven Milestone Repository + http://s3.amazonaws.com/maven.springframework.org/milestone + + false + + + + diff --git a/src/main/java/log4j.properties b/src/main/java/log4j.properties new file mode 100644 index 0000000..b75d1da --- /dev/null +++ b/src/main/java/log4j.properties @@ -0,0 +1,15 @@ +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss} [%5p] %c{1}.%M - %m%n + +# Rotate log files +log4j.appender.R=org.apache.log4j.DailyRollingFileAppender +log4j.appender.R.File=cims.log + +# create a new log every day +log4j.appender.R.DatePattern='.'yyyy-MM-dd +log4j.appender.R.layout=org.apache.log4j.PatternLayout +log4j.appender.R.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss} [%5p] %c{1}.%M - %m%n + +log4j.rootLogger=WARN,stdout,R +log4j.category.org.springframework=DEBUG diff --git a/src/main/java/org/springframework/batch/spreadsheet/CalcRowCallback.java b/src/main/java/org/springframework/batch/spreadsheet/CalcRowCallback.java new file mode 100644 index 0000000..8221762 --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/CalcRowCallback.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import org.jopendocument.dom.spreadsheet.Sheet; + +/** + * This simple interface defines a callback for processing one row of a spreadsheet. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see CalcTemplate + */ +public interface CalcRowCallback { + + /** + * This method is used to map a row of data. However, for some use cases, you may need access + * to other information about the worksheet, which is why sheet is provided. + * + * @param sheet - the entire Calc worksheet + * @param row - the specific Calc row being processed + * @return a mapped object based on the row, or null + */ + public T mapRow(Sheet sheet, int row); + +} diff --git a/src/main/java/org/springframework/batch/spreadsheet/CalcTemplate.java b/src/main/java/org/springframework/batch/spreadsheet/CalcTemplate.java new file mode 100644 index 0000000..e784cae --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/CalcTemplate.java @@ -0,0 +1,166 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.jopendocument.dom.spreadsheet.Sheet; +import org.jopendocument.dom.spreadsheet.SpreadSheet; + +/** + * This utility class provides easy access to processing Open Office Calc worksheets. Code using this + * only needs to implement the callback interfaces. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see ExcelTemplate + */ +public class CalcTemplate { + + private static final Logger logger = Logger.getLogger(CalcTemplate.class); + + /** + * The file that this instance of CalcTemplate processes. + */ + private File file; + + /** + * Option to skip the first row (usually due to a header being there). + */ + private boolean skipFirstRowDefault; + + /** + * Standard policy is to NOT skip the first row of a worksheet. + */ + public CalcTemplate(File file) { + this(file, false); + } + + /** + * Set whether or not to skip the first row by default for a particular worksheet. + */ + public CalcTemplate(File file, boolean skipFirstRowDefault) { + this.file = file; + this.skipFirstRowDefault = skipFirstRowDefault; + } + + /** + * Process each row of the worksheet using the default error handler. + * + * @param - type of the object to be returned + * @param sheetNum - integer index into the row of the spreadsheet + * @param calcCallback - callback defining how to process a row of data + * @return list of T objects + */ + public List onEachRow(int sheetNum, CalcRowCallback calcCallback) { + return onEachRow(sheetNum, calcCallback, skipFirstRowDefault, new DefaultCalcTemplateErrorHandler()); + } + + /** + * Process each row of the worksheet, using an alternate error handling strategy. + * + * @param - type of the object to be returned + * @param sheetNum - integer index into the row of the spreadsheet + * @param calcCallback - callback defining how to process a row of data + * @param errorHandler - custom error handler + * @return list of T objects + */ + public List onEachRow(int sheetNum, CalcRowCallback calcCallback, CalcTemplateErrorHandler errorHandler) { + return onEachRow(sheetNum, calcCallback, skipFirstRowDefault, errorHandler); + } + + /** + * This is the work horse for row-level worksheet processing. + *

+ * 1) Read data from file.
+ * 2) Find specific worksheet.
+ * 3) Create an empty List.
+ * 4) Iterate over the worksheet, building up the list.
+ * 5) Return the list. + * + * @param - type of the object to be returned + * @param sheetNum - integer index into the row of the spreadsheet + * @param calcCallback - callback defining how to process a row of data + * @param skipFirstRow - override default setting of whether or not to skip the first row + * @param errorHandler - custom error handler + * @return list of T objects + */ + public List onEachRow(int sheetNum, CalcRowCallback calcCallback, boolean skipFirstRow, CalcTemplateErrorHandler errorHandler) { + try { + SpreadSheet spreadsheet = SpreadSheet.createFromFile(file); + Sheet sheet = spreadsheet.getSheet(sheetNum); + + List results = new ArrayList(); + + if (skipFirstRow) { + logger.debug("Skipping first row..."); + for (int row=1; row < sheet.getRowCount(); row++) { + processRow(calcCallback, results, sheet, row, errorHandler); + } + } else { + logger.debug("Skipping nuthin'!"); + for (int row=0; row < sheet.getRowCount(); row++) { + processRow(calcCallback, results, sheet, row, errorHandler); + } + } + + return results; + + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * This utility method is used to invoke the row-level callback. It also traps any + * runtime exceptions, and runs them through the error handler. + *

+ * If the callback returns null, the row is NOT added to the list. + * + * @param - type of the object to be returned + * @param calcCallback - callback defining how to process a row of data + * @param results - list that is being built up by iteration + * @param sheet - worksheet that is being processed + * @param row - index into spreadsheet row + * @param errorHandler - error handler callback + */ + private void processRow(CalcRowCallback calcCallback, List results, Sheet sheet, int row, CalcTemplateErrorHandler errorHandler) { + T rowResult = null; + try { + rowResult = calcCallback.mapRow(sheet, row); + } catch (RuntimeException e) { + rowResult = errorHandler.handleException(sheet, row, e); + } + if (rowResult != null) { + results.add(rowResult); + } + } + + public boolean isSkipFirstRowDefault() { + return skipFirstRowDefault; + } + + public void setSkipFirstRowDefault(boolean skipFirstRowDefault) { + this.skipFirstRowDefault = skipFirstRowDefault; + } + +} diff --git a/src/main/java/org/springframework/batch/spreadsheet/CalcTemplateErrorHandler.java b/src/main/java/org/springframework/batch/spreadsheet/CalcTemplateErrorHandler.java new file mode 100644 index 0000000..b6abad5 --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/CalcTemplateErrorHandler.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import org.jopendocument.dom.spreadsheet.Sheet; + +/** + * This interface defines a strategy for handling exceptions thrown while iterating over + * an Open Office Calc spreadsheet. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see CalcTemplate + */ +public interface CalcTemplateErrorHandler { + + public T handleException(Sheet sheet, int row, RuntimeException e); + +} diff --git a/src/main/java/org/springframework/batch/spreadsheet/CalcUtil.java b/src/main/java/org/springframework/batch/spreadsheet/CalcUtil.java new file mode 100644 index 0000000..6d4d1dd --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/CalcUtil.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import org.jdom.Attribute; +import org.jopendocument.dom.spreadsheet.MutableCell; +import org.jopendocument.dom.spreadsheet.Sheet; +import org.jopendocument.dom.spreadsheet.SpreadSheet; + +/** + * This class provides some convenience functions to help with processing Open Office Calc spreadsheets. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see CalcTemplate + */ +public class CalcUtil { + + /** + * Fetches the value of a cell found at (row, column). + * + * @param sheet - worksheet where the cell is located + * @param column + * @param row + * @return the value stored at the given cell coordinates + */ + public static String getAttr(Sheet sheet, int column, int row) { + MutableCell cell = sheet.getCellAt(column, row); + String results = cell.getValue().toString(); + if (results == null || results.equals("")) { + results = ((Attribute)cell.getElement().getAttributes().get(0)).getValue(); + } + return results.equals("") ? null : results; + } + +} diff --git a/src/main/java/org/springframework/batch/spreadsheet/DefaultCalcTemplateErrorHandler.java b/src/main/java/org/springframework/batch/spreadsheet/DefaultCalcTemplateErrorHandler.java new file mode 100644 index 0000000..0d49acd --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/DefaultCalcTemplateErrorHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import org.jopendocument.dom.spreadsheet.Sheet; + +/** + * This simple policy of error handling simply returns a null when an error is discovered. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see CalcTemplate + */ +public class DefaultCalcTemplateErrorHandler implements CalcTemplateErrorHandler { + + public T handleException(Sheet sheet, int row, RuntimeException e) { + return null; + } + +} diff --git a/src/main/java/org/springframework/batch/spreadsheet/DefaultExcelTemplateErrorHandler.java b/src/main/java/org/springframework/batch/spreadsheet/DefaultExcelTemplateErrorHandler.java new file mode 100644 index 0000000..c5ac573 --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/DefaultExcelTemplateErrorHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import org.apache.poi.ss.usermodel.Row; + +/** + * This simple policy of error handling simply returns a null when an error is discovered. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see ExcelTemplate + */ +public class DefaultExcelTemplateErrorHandler implements ExcelTemplateErrorHandler { + + public T handleException(Row row, RuntimeException e) { + return null; + } + +} diff --git a/src/main/java/org/springframework/batch/spreadsheet/ExcelCallbackWithoutResult.java b/src/main/java/org/springframework/batch/spreadsheet/ExcelCallbackWithoutResult.java new file mode 100644 index 0000000..951d4cf --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/ExcelCallbackWithoutResult.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import org.apache.poi.ss.usermodel.Row; + +/** + * @since 11/2/2009 + * @author Greg Turnquist + * @see ExcelTemplate + */ +public abstract class ExcelCallbackWithoutResult implements ExcelRowCallback { + + public final T mapRow(Row row) { + mapRowWithoutResult(row); + return null; + } + + protected abstract void mapRowWithoutResult(Row row); + +} diff --git a/src/main/java/org/springframework/batch/spreadsheet/ExcelRowCallback.java b/src/main/java/org/springframework/batch/spreadsheet/ExcelRowCallback.java new file mode 100644 index 0000000..e7fea7c --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/ExcelRowCallback.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import org.apache.poi.ss.usermodel.Row; + +/** + * This simple interface defines a callback for processing one row of a spreadsheet. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see ExcelTemplate + */ +public interface ExcelRowCallback { + + public T mapRow(Row row); + +} diff --git a/src/main/java/org/springframework/batch/spreadsheet/ExcelTemplate.java b/src/main/java/org/springframework/batch/spreadsheet/ExcelTemplate.java new file mode 100644 index 0000000..9937c0a --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/ExcelTemplate.java @@ -0,0 +1,253 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import java.awt.Point; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.Row; + +/** + * This utility class provides easy access to processing Microsoft Office Excel worksheets. Code using this + * only needs to implement the callback interfaces. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see CalcTemplate + */ +public class ExcelTemplate { + + /** + * The file that this instance of ExcelTemplate processes. + */ + private File file; + + /** + * Option to skip the first row (usually due to a header being there). + */ + private boolean skipFirstRowDefault; + + /** + * Standard policy is to NOT skip the first row of a worksheet. + */ + public ExcelTemplate(File file) { + this(file, false); + } + + /** + * Set whether or not to skip the first row by default for a particular worksheet. + */ + public ExcelTemplate(File file, boolean skipFirstRowDefault) { + this.file = file; + this.skipFirstRowDefault = skipFirstRowDefault; + } + + /** + * Process each row of the worksheet using the default error handler. + * + * @param - type of the object to be returned + * @param worksheetName - name of the worksheet to process + * @param excelCallback - callback defining how to process a row of data + * @return list of T objects + */ + public List onEachRow(String worksheetName, ExcelRowCallback excelCallback) { + return onEachRow(worksheetName, excelCallback, skipFirstRowDefault, new DefaultExcelTemplateErrorHandler()); + } + + /** + * Process each row of the worksheet using a customized error handler. + * + * @param - type of the object to be returned + * @param worksheetName - name of the worksheet to process + * @param excelCallback - callback defining how to process a row of data + * @param errorHandler + * @return list of T objects + */ + public List onEachRow(String worksheetName, ExcelRowCallback excelCallback, ExcelTemplateErrorHandler errorHandler) { + return onEachRow(worksheetName, excelCallback, skipFirstRowDefault, errorHandler); + } + + /** + * This is the work horse for row-level worksheet processing. + *

+ * 1) Read data from file.
+ * 3) Create an empty List.
+ * 4) Iterate over the specific worksheet, building up the list.
+ * 5) Return the list. + * + * @param - type of the object to be returned + * @param worksheetName - name of the worksheet to process + * @param excelCallback - callback defining how to process a row of data + * @param skipFirstRow + * @param errorHandler + * @return list of T objects + */ + public List onEachRow(String worksheetName, ExcelRowCallback excelCallback, boolean skipFirstRow, ExcelTemplateErrorHandler errorHandler) { + try { + InputStream inp = new FileInputStream(file); + HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(inp)); + + List results = new ArrayList(); + + if (skipFirstRow) { + boolean firstRow = true; + for (Row row : wb.getSheet(worksheetName)) { + if (firstRow) { + firstRow = false; + continue; + } + + processRow(excelCallback, errorHandler, results, row); + } + } else { + for (Row row : wb.getSheet(worksheetName)) { + processRow(excelCallback, errorHandler, results, row); + } + } + + return results; + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * This utility method is used to invoke the row-level callback. It also traps any + * runtime exceptions, and runs them through the error handler. + *

+ * If the callback returns null, the row is NOT added to the list. + * + * @param - type of the object to be returned + * @param excelCallback - callback defining how to process a row of data + * @param errorHandler + * @param results + * @param row + */ + private void processRow(ExcelRowCallback excelCallback, + ExcelTemplateErrorHandler errorHandler, List results, Row row) { + T rowResult = null; + try { + rowResult = excelCallback.mapRow(row); + } catch (RuntimeException e) { + rowResult = errorHandler.handleException(row, e); + } + if (rowResult != null) { + results.add(rowResult); + } + } + + public boolean isSkipFirstRowDefault() { + return skipFirstRowDefault; + } + + public void setSkipFirstRowDefault(boolean skipFirstRowDefault) { + this.skipFirstRowDefault = skipFirstRowDefault; + } + + /** + * The following block includes a search algorithm, where you can scan a worksheet for certain expression, and harvest + * the cell its found in. + * TODO: Write some tests for this! + */ + private enum Direction { + GOING_UP, + GOING_DOWN, + TRANSITION_DOWN, + TRANSITION_ACROSS; + } + + /** + * This function uses a search algorithm to find a cell, and return the coordinates of + * that cell. It uses a 2-dimensional search algorithm, scanning (0,0), (1,0), (0,1), + * (0,2), (1,1), (2,0), (3,0), (2,1), (1,2), (0,3)... + * + * It is limited by a finite number of steps so it won't run forever. There is + * a default, and user can increase the default, but there is still a limit. + * + * TODO: Test this. + * + * @param sheet + * @param keyPhrase + * @return Point(x=column, y=row) + */ + private Point searchForCell(HSSFSheet sheet, String keyPhrase) { + return searchForCell(sheet, keyPhrase, 1000); + } + + /** + * This is the core method, and used when the user needs to override the number of steps + * to take in searching for the cell. + * + * TODO: Test this. + * + * @param sheet + * @param keyPhrase + * @param maxSteps + * @return + */ + private Point searchForCell(HSSFSheet sheet, String keyPhrase, int maxSteps) { + int row = 0; + int column = 0; + Direction parseDirection = Direction.TRANSITION_DOWN; + int steps = 0; + while (steps < maxSteps) { + HSSFCell cell = sheet.getRow(row).getCell(column); + if (cell != null) { + if (cell.toString().equals(keyPhrase)) { + return new Point(column, row); + } + } + switch (parseDirection) { + case GOING_DOWN: + row++; column--; + steps++; + if (column == 0) parseDirection = Direction.TRANSITION_DOWN; + break; + case GOING_UP: + row--; column++; + steps++; + if (row == 0) parseDirection = Direction.TRANSITION_ACROSS; + break; + case TRANSITION_DOWN: + row++; + steps++; + parseDirection = Direction.GOING_UP; + break; + case TRANSITION_ACROSS: + column++; + steps++; + parseDirection = Direction.GOING_DOWN; + break; + } + } + throw new RuntimeException("Could not find '" + keyPhrase + "' in less than " + maxSteps + " steps."); + } + + +} diff --git a/src/main/java/org/springframework/batch/spreadsheet/ExcelTemplateErrorHandler.java b/src/main/java/org/springframework/batch/spreadsheet/ExcelTemplateErrorHandler.java new file mode 100644 index 0000000..7128d76 --- /dev/null +++ b/src/main/java/org/springframework/batch/spreadsheet/ExcelTemplateErrorHandler.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import org.apache.poi.ss.usermodel.Row; + +/** + * This interface defines a strategy for handling exceptions thrown while iterating over + * a Microsoft Office Excel spreadsheet. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see ExcelTemplate + */ +public interface ExcelTemplateErrorHandler { + + public T handleException(Row row, RuntimeException e); +} diff --git a/src/site/apt/notes.apt b/src/site/apt/notes.apt new file mode 100755 index 0000000..e69de29 diff --git a/src/site/site.xml b/src/site/site.xml new file mode 100755 index 0000000..4aac572 --- /dev/null +++ b/src/site/site.xml @@ -0,0 +1,17 @@ + + + + + + + + + +

+ + + + + + + diff --git a/src/test/java/org/springframework/batch/spreadsheet/TestCalcTemplate.java b/src/test/java/org/springframework/batch/spreadsheet/TestCalcTemplate.java new file mode 100644 index 0000000..cfe3ea2 --- /dev/null +++ b/src/test/java/org/springframework/batch/spreadsheet/TestCalcTemplate.java @@ -0,0 +1,240 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; + +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableModel; + +import org.apache.log4j.Logger; +import org.apache.poi.ss.usermodel.Row; +import org.jopendocument.dom.spreadsheet.Sheet; +import org.jopendocument.dom.spreadsheet.SpreadSheet; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.batch.spreadsheet.support.EmptyPhoneBookEntry; +import org.springframework.batch.spreadsheet.support.PhoneBookEntry; + + +/** + * @author Greg Turnquist + */ +public class TestCalcTemplate { + + private static final Logger logger = Logger.getLogger(TestCalcTemplate.class); + + private String pathname = "src" + File.separator + "test" + File.separator + "resources"; + + // TODO: Workaround (11/2/2009 GLT) - Replace this method with a real Calc spreadsheet. + @Before + public void copySpreadsheets() throws FileNotFoundException, IOException { + logger.debug("TODO: Workaround (11/2/2009 GLT) - Replace this method with a real Calc spreadsheet."); + logger.debug("Porting Excel spreadsheet to Calc..."); + File input = new File(pathname + File.separator + "phonebook_with_holes.xls"); + + ExcelTemplate et = new ExcelTemplate(input); + List entries = et.onEachRow("Sheet1", new ExcelRowCallback() { + public PhoneBookEntry mapRow(Row row) { + String name = ""; + try { name = row.getCell(0).getStringCellValue(); } catch (Exception e) {} + + String address = ""; + try { address = row.getCell(1).getStringCellValue(); } catch (Exception e) {} + + String phone = ""; + try { phone = row.getCell(2).getStringCellValue(); } catch (Exception e) {} + + return new PhoneBookEntry(name, address, phone); + } + }); + + PhoneBookEntry header = entries.get(0); + String[] columns = new String[]{header.getName(), header.getAddress(), header.getPhone()}; + + final Object[][] data = new Object[entries.size()-1][3]; + + for (int i=1; i < entries.size(); i++) { + PhoneBookEntry entry = entries.get(i); + logger.debug("Adding " + entry + " to the items to be stored in this spreadsheet."); + data[i-1] = new Object[]{entry.getName(), entry.getAddress(), entry.getPhone()}; + } + + TableModel model = new DefaultTableModel(data, columns); + + final File file = new File(pathname + File.separator + "phonebook_with_holes.ods"); + SpreadSheet.createEmpty(model).saveAs(file); + logger.debug("Done porting file."); + } + + @Test + public void testReadingSimpleCalcSpreadsheet() throws IOException { + File file = new File(pathname + File.separator + "phonebook.ods"); + CalcTemplate ct = new CalcTemplate(file); + + List results = + ct.onEachRow(0, new CalcRowCallback() { + public PhoneBookEntry mapRow(Sheet sheet, int row) { + return new PhoneBookEntry( + CalcUtil.getAttr(sheet, 0, row), + CalcUtil.getAttr(sheet, 1, row), + CalcUtil.getAttr(sheet, 2, row)); + } + }); + + Assert.assertEquals(2, results.size()); + + Assert.assertEquals("Name", results.get(0).getName()); + Assert.assertEquals("Address", results.get(0).getAddress()); + Assert.assertEquals("Phone", results.get(0).getPhone()); + + Assert.assertEquals("Peter Gibbons", results.get(1).getName()); + Assert.assertEquals("123 ABC Drive", results.get(1).getAddress()); + Assert.assertEquals("555-821-2123", results.get(1).getPhone()); + } + + @Test + public void testReadingSimpleCalcSpreadsheetSkippingHeader() { + File file = new File(pathname + File.separator + "phonebook.ods"); + CalcTemplate et = new CalcTemplate(file, true); + List results = + et.onEachRow(0, new CalcRowCallback() { + public PhoneBookEntry mapRow(Sheet sheet, int row) { + return new PhoneBookEntry( + CalcUtil.getAttr(sheet, 0, row), + CalcUtil.getAttr(sheet, 1, row), + CalcUtil.getAttr(sheet, 2, row) + ); + } + }); + + Assert.assertEquals(1, results.size()); + + Assert.assertEquals("Peter Gibbons", results.get(0).getName()); + Assert.assertEquals("123 ABC Drive", results.get(0).getAddress()); + Assert.assertEquals("555-821-2123", results.get(0).getPhone()); + } + + @Test + public void testReadingCalcSpreadsheetWithHolesUsingDefaultErrorHandling() { + File file = new File(pathname + File.separator + "phonebook_with_holes.ods"); + CalcTemplate et = new CalcTemplate(file, true); + List results = + et.onEachRow(0, new CalcRowCallback() { + public PhoneBookEntry mapRow(Sheet sheet, int row) { + PhoneBookEntry entry = new PhoneBookEntry( + CalcUtil.getAttr(sheet, 0, row), + CalcUtil.getAttr(sheet, 1, row), + CalcUtil.getAttr(sheet, 2, row) + ); + return entry; + } + }); + + Assert.assertEquals(1, results.size()); + + Assert.assertEquals("Peter Gibbons", results.get(0).getName()); + Assert.assertEquals("123 ABC Drive", results.get(0).getAddress()); + Assert.assertEquals("555-821-2123", results.get(0).getPhone()); + } + + @Test + public void testReadingCalcSpreadsheetWithHoles2() { + File file = new File(pathname + File.separator + "phonebook_with_holes.ods"); + CalcTemplate et = new CalcTemplate(file, true); + List results = + et.onEachRow(0, new CalcRowCallback() { + public PhoneBookEntry mapRow(Sheet sheet, int row) { + String name = null; + try { name = CalcUtil.getAttr(sheet, 0, row); } catch (Exception e) {} + + String address = null; + try { address = CalcUtil.getAttr(sheet, 1, row); } catch (Exception e) {} + + String phone = null; + try { phone = CalcUtil.getAttr(sheet, 2, row); } catch (Exception e) {} + + return new PhoneBookEntry(name, address, phone); + } + }); + + Assert.assertEquals(4, results.size()); + + Assert.assertEquals("Peter Gibbons", results.get(0).getName()); + Assert.assertEquals("123 ABC Drive", results.get(0).getAddress()); + Assert.assertEquals("555-821-2123", results.get(0).getPhone()); + + Assert.assertEquals("Joanna", results.get(1).getName()); + Assert.assertNull(results.get(1).getAddress()); + Assert.assertEquals("555-915-9900", results.get(1).getPhone()); + + Assert.assertNull(results.get(2).getName()); + Assert.assertEquals("Corp HQ", results.get(2).getAddress()); + Assert.assertEquals("555-321-9502", results.get(2).getPhone()); + + Assert.assertEquals("Bill Lumbergh", results.get(3).getName()); + Assert.assertEquals("his cubicle", results.get(3).getAddress()); + Assert.assertNull(results.get(3).getPhone()); + } + + @Test + public void testReadingCalcSpreadsheetWithHolesUsingSpecialErrorHandling() { + File file = new File(pathname + File.separator + "phonebook_with_holes.ods"); + CalcTemplate et = new CalcTemplate(file, true); + + List results = + et.onEachRow(0, + new CalcRowCallback() { + public PhoneBookEntry mapRow(Sheet sheet, int row) { + return new PhoneBookEntry( + CalcUtil.getAttr(sheet, 0, row), + CalcUtil.getAttr(sheet, 1, row), + CalcUtil.getAttr(sheet, 2, row) + ); + } + }, + new CalcTemplateErrorHandler() { + public PhoneBookEntry handleException(Sheet sheet, int row, RuntimeException e) { + return new EmptyPhoneBookEntry(); + } + } + ); + + Assert.assertEquals(4, results.size()); + + Assert.assertEquals("Peter Gibbons", results.get(0).getName()); + Assert.assertEquals("123 ABC Drive", results.get(0).getAddress()); + Assert.assertEquals("555-821-2123", results.get(0).getPhone()); + + Assert.assertEquals(EmptyPhoneBookEntry.NAME, results.get(1).getName()); + Assert.assertEquals(EmptyPhoneBookEntry.ADDRESS, results.get(1).getAddress()); + Assert.assertEquals(EmptyPhoneBookEntry.PHONE, results.get(1).getPhone()); + + Assert.assertEquals(EmptyPhoneBookEntry.NAME, results.get(2).getName()); + Assert.assertEquals(EmptyPhoneBookEntry.ADDRESS, results.get(2).getAddress()); + Assert.assertEquals(EmptyPhoneBookEntry.PHONE, results.get(2).getPhone()); + + Assert.assertEquals(EmptyPhoneBookEntry.NAME, results.get(3).getName()); + Assert.assertEquals(EmptyPhoneBookEntry.ADDRESS, results.get(3).getAddress()); + Assert.assertEquals(EmptyPhoneBookEntry.PHONE, results.get(3).getPhone()); + } + +} diff --git a/src/test/java/org/springframework/batch/spreadsheet/TestExcelTemplate.java b/src/test/java/org/springframework/batch/spreadsheet/TestExcelTemplate.java new file mode 100644 index 0000000..205396f --- /dev/null +++ b/src/test/java/org/springframework/batch/spreadsheet/TestExcelTemplate.java @@ -0,0 +1,187 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet; + +import java.io.File; +import java.util.List; + +import junit.framework.Assert; + +import org.apache.poi.ss.usermodel.Row; +import org.junit.Test; +import org.springframework.batch.spreadsheet.support.EmptyPhoneBookEntry; +import org.springframework.batch.spreadsheet.support.PhoneBookEntry; + +/** + * @author Greg Turnquist + */ +public class TestExcelTemplate { + + private String pathname = "src" + File.separator + "test" + File.separator + "resources"; + + @Test + public void testReadingSimpleExcelSpreadsheetWithoutHeaderHandling() { + File file = new File(pathname + File.separator + "phonebook.xls"); + ExcelTemplate et = new ExcelTemplate(file); + List results = + et.onEachRow("Sheet1", new ExcelRowCallback() { + public PhoneBookEntry mapRow(Row row) { + return new PhoneBookEntry( + row.getCell(0).getStringCellValue(), + row.getCell(1).getStringCellValue(), + row.getCell(2).getStringCellValue() + ); + } + }); + + Assert.assertEquals(2, results.size()); + + Assert.assertEquals("Name", results.get(0).getName()); + Assert.assertEquals("Address", results.get(0).getAddress()); + Assert.assertEquals("Phone", results.get(0).getPhone()); + + Assert.assertEquals("Peter Gibbons", results.get(1).getName()); + Assert.assertEquals("123 ABC Drive", results.get(1).getAddress()); + Assert.assertEquals("555-821-2123", results.get(1).getPhone()); + } + + @Test + public void testReadingSimpleExcelSpreadsheetSkippingHeader() { + File file = new File(pathname + File.separator + "phonebook.xls"); + ExcelTemplate et = new ExcelTemplate(file, true); + List results = + et.onEachRow("Sheet1", new ExcelRowCallback() { + public PhoneBookEntry mapRow(Row row) { + return new PhoneBookEntry( + row.getCell(0).getStringCellValue(), + row.getCell(1).getStringCellValue(), + row.getCell(2).getStringCellValue() + ); + } + }); + + Assert.assertEquals(1, results.size()); + + Assert.assertEquals("Peter Gibbons", results.get(0).getName()); + Assert.assertEquals("123 ABC Drive", results.get(0).getAddress()); + Assert.assertEquals("555-821-2123", results.get(0).getPhone()); + } + + @Test + public void testReadingExcelSpreadsheetWithHolesUsingDefaultErrorHandling() { + File file = new File(pathname + File.separator + "phonebook_with_holes.xls"); + ExcelTemplate et = new ExcelTemplate(file, true); + List results = + et.onEachRow("Sheet1", new ExcelRowCallback() { + public PhoneBookEntry mapRow(Row row) { + return new PhoneBookEntry( + row.getCell(0).getStringCellValue(), + row.getCell(1).getStringCellValue(), + row.getCell(2).getStringCellValue() + ); + } + }); + + Assert.assertEquals(1, results.size()); + + Assert.assertEquals("Peter Gibbons", results.get(0).getName()); + Assert.assertEquals("123 ABC Drive", results.get(0).getAddress()); + Assert.assertEquals("555-821-2123", results.get(0).getPhone()); + } + + @Test + public void testReadingExcelSpreadsheetWithHoles2() { + File file = new File(pathname + File.separator + "phonebook_with_holes.xls"); + ExcelTemplate et = new ExcelTemplate(file, true); + List results = + et.onEachRow("Sheet1", new ExcelRowCallback() { + public PhoneBookEntry mapRow(Row row) { + String name = null; + try { name = row.getCell(0).getStringCellValue(); } catch (Exception e) {} + + String address = null; + try { address = row.getCell(1).getStringCellValue(); } catch (Exception e) {} + + String phone = null; + try { phone = row.getCell(2).getStringCellValue(); } catch (Exception e) {} + + return new PhoneBookEntry(name, address, phone); + } + }); + + Assert.assertEquals(4, results.size()); + + Assert.assertEquals("Peter Gibbons", results.get(0).getName()); + Assert.assertEquals("123 ABC Drive", results.get(0).getAddress()); + Assert.assertEquals("555-821-2123", results.get(0).getPhone()); + + Assert.assertEquals("Joanna", results.get(1).getName()); + Assert.assertNull(results.get(1).getAddress()); + Assert.assertEquals("555-915-9900", results.get(1).getPhone()); + + Assert.assertNull(results.get(2).getName()); + Assert.assertEquals("Corp HQ", results.get(2).getAddress()); + Assert.assertEquals("555-321-9502", results.get(2).getPhone()); + + Assert.assertEquals("Bill Lumbergh", results.get(3).getName()); + Assert.assertEquals("his cubicle", results.get(3).getAddress()); + Assert.assertNull(results.get(3).getPhone()); + } + + @Test + public void testReadingExcelSpreadsheetWithHolesUsingSpecialErrorHandling() { + File file = new File(pathname + File.separator + "phonebook_with_holes.xls"); + ExcelTemplate et = new ExcelTemplate(file, true); + + List results = + et.onEachRow("Sheet1", + new ExcelRowCallback() { + public PhoneBookEntry mapRow(Row row) { + return new PhoneBookEntry( + row.getCell(0).getStringCellValue(), + row.getCell(1).getStringCellValue(), + row.getCell(2).getStringCellValue() + ); + } + }, + new ExcelTemplateErrorHandler() { + public PhoneBookEntry handleException(Row row, RuntimeException e) { + return new EmptyPhoneBookEntry(); + } + } + ); + + Assert.assertEquals(4, results.size()); + + Assert.assertEquals("Peter Gibbons", results.get(0).getName()); + Assert.assertEquals("123 ABC Drive", results.get(0).getAddress()); + Assert.assertEquals("555-821-2123", results.get(0).getPhone()); + + Assert.assertEquals(EmptyPhoneBookEntry.NAME, results.get(1).getName()); + Assert.assertEquals(EmptyPhoneBookEntry.ADDRESS, results.get(1).getAddress()); + Assert.assertEquals(EmptyPhoneBookEntry.PHONE, results.get(1).getPhone()); + + Assert.assertEquals(EmptyPhoneBookEntry.NAME, results.get(2).getName()); + Assert.assertEquals(EmptyPhoneBookEntry.ADDRESS, results.get(2).getAddress()); + Assert.assertEquals(EmptyPhoneBookEntry.PHONE, results.get(2).getPhone()); + + Assert.assertEquals(EmptyPhoneBookEntry.NAME, results.get(3).getName()); + Assert.assertEquals(EmptyPhoneBookEntry.ADDRESS, results.get(3).getAddress()); + Assert.assertEquals(EmptyPhoneBookEntry.PHONE, results.get(3).getPhone()); + } + +} diff --git a/src/test/java/org/springframework/batch/spreadsheet/support/EmptyPhoneBookEntry.java b/src/test/java/org/springframework/batch/spreadsheet/support/EmptyPhoneBookEntry.java new file mode 100644 index 0000000..f35f2c6 --- /dev/null +++ b/src/test/java/org/springframework/batch/spreadsheet/support/EmptyPhoneBookEntry.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet.support; + +import org.springframework.batch.spreadsheet.CalcTemplate; +import org.springframework.batch.spreadsheet.ExcelTemplate; + +/** + * Simple POJO to represent an empty phone book entry. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see CalcTemplate + * @see ExcelTemplate + */ +public class EmptyPhoneBookEntry extends PhoneBookEntry { + + public static final String NAME = "No name"; + public static final String ADDRESS = "No address"; + public static final String PHONE = "No phone number"; + + public EmptyPhoneBookEntry() { + super(NAME, ADDRESS, PHONE); + } +} diff --git a/src/test/java/org/springframework/batch/spreadsheet/support/PhoneBookEntry.java b/src/test/java/org/springframework/batch/spreadsheet/support/PhoneBookEntry.java new file mode 100644 index 0000000..848c3a9 --- /dev/null +++ b/src/test/java/org/springframework/batch/spreadsheet/support/PhoneBookEntry.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2009 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.springframework.batch.spreadsheet.support; + +import org.springframework.batch.spreadsheet.CalcTemplate; +import org.springframework.batch.spreadsheet.ExcelTemplate; + +/** + * Simple POJO to represent an empty phone book entry. + * + * @since 11/2/2009 + * @author Greg Turnquist + * @see CalcTemplate + * @see ExcelTemplate + */ +public class PhoneBookEntry { + + private String name; + private String address; + private String phone; + + public PhoneBookEntry() { + } + + public PhoneBookEntry(String name, String address, String phone) { + this.name = name; + this.address = address; + this.phone = phone; + } + + public String toString() { + return "Name = " + name + " Address = " + address + " Phone = " + phone; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + +} \ No newline at end of file diff --git a/src/test/resources/phonebook.ods b/src/test/resources/phonebook.ods new file mode 100644 index 0000000..c7bd0f2 Binary files /dev/null and b/src/test/resources/phonebook.ods differ diff --git a/src/test/resources/phonebook.xls b/src/test/resources/phonebook.xls new file mode 100644 index 0000000..9f1419f Binary files /dev/null and b/src/test/resources/phonebook.xls differ diff --git a/src/test/resources/phonebook_with_holes.ods b/src/test/resources/phonebook_with_holes.ods new file mode 100644 index 0000000..415bab1 Binary files /dev/null and b/src/test/resources/phonebook_with_holes.ods differ diff --git a/src/test/resources/phonebook_with_holes.xls b/src/test/resources/phonebook_with_holes.xls new file mode 100644 index 0000000..cebf89e Binary files /dev/null and b/src/test/resources/phonebook_with_holes.xls differ