/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.isis.core.runtime.fixturedomainservice;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.ObjectSpecificationException;
import org.apache.isis.core.metamodel.spec.feature.Contributed;
import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
public class ObjectFixtureFilePersistor {
private static final Logger LOG = LoggerFactory.getLogger(ObjectFixtureFilePersistor.class);
public Set<Object> loadData(final Reader reader) throws IOException {
final Set<Object> objects = new HashSet<Object>();
final BufferedReader buffer = new BufferedReader(reader);
final LoadedObjects loaded = new LoadedObjects(objects, specificationLoader, getPersistenceSession());
String line;
ObjectAdapter object = null;
int lineNo = 0;
try {
while ((line = buffer.readLine()) != null) {
lineNo++;
if (line.trim().startsWith("#")) {
continue;
} else if (line.startsWith(" ")) {
loadFieldData(object, loaded, line);
} else {
if (object != null && !object.representsPersistent()) {
getPersistenceSession().makePersistentInTransaction(object);
}
object = loaded.get(line);
}
}
if (object != null && !object.representsPersistent()) {
getPersistenceSession().makePersistentInTransaction(object);
}
} catch (final Exception e) {
throw new FixtureException("failed to load data at line " + lineNo, e);
}
return objects;
}
private void loadFieldData(final ObjectAdapter object, final LoadedObjects loaded, final String line) {
final int pos = line.indexOf(':');
if (pos == -1) {
throw new FixtureException("no colon (:) in: " + line.trim());
}
final String name = line.substring(0, pos).trim();
String data = line.substring(pos + 1).trim();
try {
final ObjectAssociation association = object.getSpecification().getAssociation(name);
if (data.trim().length() == 0) {
if ( association instanceof OneToOneAssociation &&
!association.isEmpty(object, InteractionInitiatedBy.FRAMEWORK)) {
final OneToOneAssociation property = (OneToOneAssociation) association;
property.set(object, null, InteractionInitiatedBy.FRAMEWORK);
}
} else {
if (association.isOneToManyAssociation()) {
final String[] ids = data.split(" ");
final ObjectAdapter[] elements = new ObjectAdapter[ids.length];
for (int i = 0; i < ids.length; i++) {
elements[i] = loaded.get(ids[i]);
}
final ObjectAdapter collection = association.get(object, InteractionInitiatedBy.FRAMEWORK);
final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(collection);
facet.init(collection, elements);
} else if (association.getSpecification().isParseable()) {
data = data.replaceAll("\\n", "\n");
final ParseableFacet facet = association.getSpecification().getFacet(ParseableFacet.class);
final ObjectAdapter value = facet.parseTextEntry(null, data, InteractionInitiatedBy.FRAMEWORK);
((OneToOneAssociation) association).initAssociation(object, value);
} else if (association.isOneToOneAssociation()) {
final ObjectAdapter value = loaded.get(data);
((OneToOneAssociation) association).initAssociation(object, value);
}
}
} catch (final ObjectSpecificationException e) {
LOG.info("no field for '" + name + "', skipping entry: " + data);
}
}
public void save(final Set<Object> objects, final Writer out) throws IOException {
final PrintWriter writer = new PrintWriter(out);
final SavedObjects saved = new SavedObjects();
for (final Object object : objects) {
final ObjectAdapter adapter = getPersistenceSession().adapterFor(object);
saveData(writer, adapter, saved);
}
out.close();
}
private void saveData(final PrintWriter writer, final ObjectAdapter adapter, final SavedObjects saved) {
final String id = saved.getId(adapter);
writer.println(adapter.getSpecification().getFullIdentifier() + "#" + id);
final ObjectSpecification adapterSpec = adapter.getSpecification();
final List<ObjectAssociation> associations = adapterSpec.getAssociations(Contributed.EXCLUDED);
for (final ObjectAssociation association : associations) {
if (association.isNotPersisted()) {
continue;
}
final ObjectAdapter associatedObject = association.get(adapter, InteractionInitiatedBy.FRAMEWORK);
final boolean isEmpty = association.isEmpty(adapter, InteractionInitiatedBy.FRAMEWORK);
final String associationId = association.getId();
writer.write(" " + associationId + ": ");
if (isEmpty) {
writer.println();
continue;
}
if (association.isOneToManyAssociation()) {
final CollectionFacet facet = associatedObject.getSpecification().getFacet(CollectionFacet.class);
for (final ObjectAdapter element : facet.iterable(associatedObject)) {
final String refId = saved.getId(element);
final String cls = element.getSpecification().getFullIdentifier();
writer.print(cls + "#" + refId + " ");
}
writer.println();
} else if (association.getSpecification().isParseable()) {
final ParseableFacet facet = associatedObject.getSpecification().getFacet(ParseableFacet.class);
String encodedValue = facet.parseableTitle(associatedObject);
encodedValue = encodedValue.replaceAll("\n", "\\n");
writer.println(encodedValue);
} else if (association.isOneToOneAssociation()) {
final String refId = saved.getId(associatedObject);
final String cls = associatedObject.getSpecification().getFullIdentifier();
writer.println(cls + "#" + refId);
}
}
}
@javax.inject.Inject
IsisSessionFactory isisSessionFactory;
protected PersistenceSession getPersistenceSession() {
return isisSessionFactory.getCurrentSession().getPersistenceSession();
}
@javax.inject.Inject
SpecificationLoader specificationLoader;
}
class LoadedObjects {
private final Map<String, ObjectAdapter> idMap = Maps.newHashMap();
private final Set<Object> objects;
private final SpecificationLoader specificationLoader;
private final PersistenceSession persistenceSession;
public LoadedObjects(
final Set<Object> objects,
final SpecificationLoader specificationLoader,
final PersistenceSession persistenceSession) {
this.objects = objects;
this.specificationLoader = specificationLoader;
this.persistenceSession = persistenceSession;
}
public ObjectAdapter get(final String data) {
final int pos = data.indexOf('#');
if (pos == -1) {
throw new FixtureException("load failed - trying to read non-reference data as a reference: " + data);
}
final String id = data.substring(pos + 1);
ObjectAdapter object = idMap.get(id);
if (object == null) {
final String className = data.substring(0, pos);
final ObjectSpecification specification = specificationLoader.loadSpecification(className);
object = persistenceSession.createTransientInstance(specification);
idMap.put(id, object);
objects.add(object.getObject());
}
return object;
}
}
class SavedObjects {
private int id = 1;
private final Map<ObjectAdapter, String> idMap = new HashMap<ObjectAdapter, String>();
public String getId(final ObjectAdapter object) {
String idString = idMap.get(object);
if (idString == null) {
id++;
idMap.put(object, "" + id);
idString = "" + id;
}
return idString;
}
}