001// Generated by delombok at Mon Oct 02 22:22:47 BST 2023 002/* 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 */ 020package org.apache.causeway.extensions.excel.testing; 021 022import java.io.InputStream; 023import java.net.URL; 024import java.util.*; 025import javax.inject.Inject; 026import javax.inject.Named; 027import org.apache.causeway.applib.annotation.DomainObject; 028import org.apache.causeway.applib.annotation.Programmatic; 029import org.apache.causeway.applib.annotation.PropertyLayout; 030import org.apache.causeway.applib.services.metamodel.BeanSort; 031import org.apache.causeway.applib.services.repository.RepositoryService; 032import org.apache.causeway.applib.value.Blob; 033import org.apache.causeway.commons.internal.base._Bytes; 034import org.apache.causeway.commons.internal.base._NullSafe; 035import org.apache.causeway.commons.internal.collections._Lists; 036import org.apache.causeway.commons.internal.collections._Maps; 037import org.apache.causeway.core.metamodel.spec.ObjectSpecification; 038import org.apache.causeway.core.metamodel.specloader.SpecificationLoader; 039import org.apache.causeway.extensions.excel.applib.CausewayModuleExtExcelApplib; 040import org.apache.causeway.extensions.excel.applib.ExcelService; 041import org.apache.causeway.testing.fixtures.applib.fixturescripts.FixtureResultList; 042import org.apache.causeway.testing.fixtures.applib.fixturescripts.FixtureScript; 043import org.apache.causeway.testing.fixtures.applib.fixturescripts.FixtureScriptWithExecutionStrategy; 044import org.apache.causeway.testing.fixtures.applib.fixturescripts.FixtureScripts; 045 046/** 047 * @since 2.0 {@index} 048 */ 049@Named(ExcelFixture.LOGICAL_TYPE_NAME) 050@DomainObject 051public class ExcelFixture extends FixtureScript implements FixtureScriptWithExecutionStrategy { 052 public static final String LOGICAL_TYPE_NAME = CausewayModuleExtExcelApplib.NAMESPACE + ".ExcelFixture"; 053 private final List<Class<?>> classes; 054 @Inject 055 SpecificationLoader specLoader; 056 @Inject 057 ExcelService excelService; 058 @Inject 059 RepositoryService repositoryService; 060 061 public ExcelFixture(final URL excelResource, final Class<?>... classes) { 062 this(excelResource, Arrays.asList(classes)); 063 } 064 065 public ExcelFixture(final URL excelResource, final List<Class<?>> classes) { 066 this(classes); 067 setExcelResource(excelResource); 068 } 069 070 public ExcelFixture(final Blob upload, final Class<?>... classes) { 071 this(upload, Arrays.asList(classes)); 072 } 073 074 public ExcelFixture(final Blob blob, final List<Class<?>> classes) { 075 this(classes); 076 setBlob(blob); 077 } 078 079 private ExcelFixture(final List<Class<?>> classes) { 080 for (Class<?> cls : classes) { 081 final org.apache.causeway.applib.services.metamodel.BeanSort beanSort = Optional.ofNullable(specLoader).flatMap(sl -> sl.specForType(cls)).filter(_NullSafe::isPresent).map(ObjectSpecification::getBeanSort).orElse(BeanSort.UNKNOWN); 082 if (!beanSort.isViewModel() && !beanSort.isEntity()) { 083 throw new IllegalArgumentException(String.format("Class \'%s\' does not implement \'%s\', nor is it persistable", cls.getSimpleName(), ExcelFixtureRowHandler.class.getSimpleName())); 084 } 085 } 086 this.classes = classes; 087 } 088 089 /** 090 * Input, optional: defines the name of the resource, used as a suffix to override {@link #getQualifiedName()} 091 * (disambiguate items when added to {@link FixtureResultList} if multiple instances of {@link ExcelFixture} are 092 * used with different excel spreadsheets). 093 */ 094 @PropertyLayout(sequence = "1.1") 095 private String excelResourceName; 096 097 @Programmatic 098 @Override 099 public String getQualifiedName() { 100 return super.getQualifiedName() + (getExcelResourceName() != null ? "-" + getExcelResourceName() : ""); 101 } 102 103 /** 104 * Input, mandatory ... the Excel spreadsheet to read. 105 */ 106 @PropertyLayout(sequence = "1.2") 107 private URL excelResource; 108 /** 109 * Input, mandatory ... the Excel spreadsheet to read. 110 */ 111 private Blob blob; 112 /** 113 * Output: all the objects created by this fixture. 114 */ 115 private final List objects = _Lists.newArrayList(); 116 /** 117 * Output: the objects created by this fixture, for a specific persistable/row handler class. 118 */ 119 private final Map<Class<?>, List<Object>> objectsByClass = _Maps.newHashMap(); 120 121 @Override 122 protected void execute(final ExecutionContext ec) { 123 if (blob == null) { 124 byte[] bytes = getBytes(); 125 blob = new Blob("unused", ExcelService.XSLX_MIME_TYPE, bytes); 126 } 127 for (Class<?> cls : classes) { 128 final List<?> rowObjects = excelService.fromExcel(blob, cls, cls.getSimpleName()); 129 Object previousRow = null; 130 for (final Object rowObj : rowObjects) { 131 final List<Object> createdObjects = create(rowObj, ec, previousRow); 132 if (createdObjects != null) { 133 addToMap(cls, createdObjects); 134 addToCombined(createdObjects); 135 } 136 previousRow = rowObj; 137 } 138 } 139 } 140 141 private List<Object> create(final Object rowObj, final ExecutionContext ec, final Object previousRow) { 142 if (rowObj instanceof ExcelFixtureRowHandler) { 143 final ExcelFixtureRowHandler rowHandler = (ExcelFixtureRowHandler) rowObj; 144 return rowHandler.handleRow(ec, this, previousRow); 145 } else { 146 repositoryService.persist(rowObj); 147 ec.addResult(this, rowObj); 148 return Collections.singletonList(rowObj); 149 } 150 } 151 152 private void addToMap(final Class<?> cls, final List<Object> createdObjects) { 153 List<Object> objectList = objectsByClass.get(cls); 154 if (objectList == null) { 155 objectList = _Lists.newArrayList(); 156 this.objectsByClass.put(cls, objectList); 157 } 158 objectList.addAll(createdObjects); 159 } 160 161 private void addToCombined(final List<Object> createdObjects) { 162 this.objects.addAll(createdObjects); 163 } 164 165 private byte[] bytes; 166 167 private byte[] getBytes() { 168 if (bytes == null) { 169 if (blob != null) { 170 bytes = blob.getBytes(); 171 } else { 172 bytes = readBytes(); 173 } 174 } 175 return bytes; 176 } 177 178 private byte[] readBytes() { 179 try (InputStream is = getExcelResource().openStream()) { 180 return _Bytes.of(is); 181 } catch (Exception e) { 182 throw new IllegalArgumentException("Could not read from resource: " + getExcelResource()); 183 } 184 } 185 186 @Override 187 public FixtureScripts.MultipleExecutionStrategy getMultipleExecutionStrategy() { 188 return FixtureScripts.MultipleExecutionStrategy.EXECUTE_ONCE_BY_VALUE; 189 } 190 191 @Override 192 public boolean equals(final Object o) { 193 if (this == o) return true; 194 if (o == null || getClass() != o.getClass()) return false; 195 final ExcelFixture that = (ExcelFixture) o; 196 return Arrays.equals(getBytes(), that.getBytes()); 197 } 198 199 @Override 200 public int hashCode() { 201 return Arrays.hashCode(getBytes()); 202 } 203 204 /** 205 * Input, optional: defines the name of the resource, used as a suffix to override {@link #getQualifiedName()} 206 * (disambiguate items when added to {@link FixtureResultList} if multiple instances of {@link ExcelFixture} are 207 * used with different excel spreadsheets). 208 */ 209 @java.lang.SuppressWarnings("all") 210 public String getExcelResourceName() { 211 return this.excelResourceName; 212 } 213 214 /** 215 * Input, optional: defines the name of the resource, used as a suffix to override {@link #getQualifiedName()} 216 * (disambiguate items when added to {@link FixtureResultList} if multiple instances of {@link ExcelFixture} are 217 * used with different excel spreadsheets). 218 */ 219 @java.lang.SuppressWarnings("all") 220 public void setExcelResourceName(final String excelResourceName) { 221 this.excelResourceName = excelResourceName; 222 } 223 224 /** 225 * Input, mandatory ... the Excel spreadsheet to read. 226 */ 227 @java.lang.SuppressWarnings("all") 228 public URL getExcelResource() { 229 return this.excelResource; 230 } 231 232 /** 233 * Input, mandatory ... the Excel spreadsheet to read. 234 */ 235 @java.lang.SuppressWarnings("all") 236 public void setExcelResource(final URL excelResource) { 237 this.excelResource = excelResource; 238 } 239 240 /** 241 * Input, mandatory ... the Excel spreadsheet to read. 242 */ 243 @java.lang.SuppressWarnings("all") 244 public Blob getBlob() { 245 return this.blob; 246 } 247 248 /** 249 * Input, mandatory ... the Excel spreadsheet to read. 250 */ 251 @java.lang.SuppressWarnings("all") 252 public void setBlob(final Blob blob) { 253 this.blob = blob; 254 } 255 256 /** 257 * Output: all the objects created by this fixture. 258 */ 259 @java.lang.SuppressWarnings("all") 260 public List getObjects() { 261 return this.objects; 262 } 263 264 /** 265 * Output: the objects created by this fixture, for a specific persistable/row handler class. 266 */ 267 @java.lang.SuppressWarnings("all") 268 public Map<Class<?>, List<Object>> getObjectsByClass() { 269 return this.objectsByClass; 270 } 271}