/**
* 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.services.memento;
import java.util.List;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.apache.isis.applib.annotation.DomainService;
import org.apache.isis.applib.annotation.NatureOfService;
import org.apache.isis.applib.annotation.Programmatic;
import org.apache.isis.applib.services.memento.MementoService;
import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
/**
* This service provides a mechanism by which a serializable memento of arbitrary state can be created. Most
* commonly this is in support of implementing the {@link org.apache.isis.applib.ViewModel} interface.
*
* <p>
* This implementation has no UI and there are no other implementations of the service API, and so it annotated
* with {@link org.apache.isis.applib.annotation.DomainService}. Because this class is implemented in core, this means
* that it is automatically registered and available for use; no further configuration is required.
*/
@DomainService(
nature = NatureOfService.DOMAIN,
menuOrder = "" + Integer.MAX_VALUE
)
public class MementoServiceDefault implements MementoService {
static class MementoDefault implements Memento {
private final boolean noEncoding;
private final Document doc;
private final UrlEncodingService urlEncodingService;
MementoDefault(boolean noEncoding, final UrlEncodingService urlEncodingService) {
this(DocumentHelper.createDocument(), noEncoding, urlEncodingService);
doc.addElement("memento");
}
MementoDefault(
Document doc,
boolean noEncoding,
final UrlEncodingService urlEncodingService) {
this.doc = doc;
this.noEncoding = noEncoding;
this.urlEncodingService = urlEncodingService;
}
@Override
public Memento set(String name, Object value) {
final Element el = doc.getRootElement();
Dom4jUtil.addChild(el, name, value);
return this;
}
@Override
public <T> T get(String name, Class<T> cls) {
final Element el = doc.getRootElement();
return Dom4jUtil.getChild(el, name, cls);
}
@Override
public String asString() {
final String xmlStr = Dom4jUtil.asString(doc);
return encode(xmlStr);
}
protected String encode(final String xmlStr) {
return noEncoding ? xmlStr : urlEncodingService.encode(xmlStr);
}
private static final Function<Element, String> ELEMENT_NAME = new Function<Element, String>(){
@Override
public String apply(final Element input) {
return input.getName();
}
};
@Override
public Set<String> keySet() {
Element element = doc.getRootElement();
@SuppressWarnings("unchecked")
List<Element> elements = element.elements();
return Sets.newLinkedHashSet(Iterables.transform(elements, ELEMENT_NAME));
}
// //////////////////////////////////////
@Override
public String toString() {
return Dom4jUtil.asString(doc);
}
}
// //////////////////////////////////////
private boolean noEncoding;
public MementoServiceDefault() {
this.noEncoding = false;
}
/**
* Not public API.
*/
@Programmatic
public MementoServiceDefault withNoEncoding() {
this.noEncoding = true;
return this;
}
// //////////////////////////////////////
@Programmatic
@Override
public Memento create() {
return new MementoDefault(noEncoding, urlEncodingService);
}
@Programmatic
@Override
public Memento parse(String str) {
String xmlStr;
if (noEncoding) {
xmlStr = str;
} else {
xmlStr = urlEncodingService.decode(str);
}
final Document doc = Dom4jUtil.parse(xmlStr);
return new MementoDefault(doc, noEncoding, urlEncodingService);
}
@Programmatic
@Override
public boolean canSet(final Object input) {
return input == null || Dom4jUtil.isSupportedClass(input.getClass());
}
// //////////////////////////////////////
@javax.inject.Inject
UrlEncodingService urlEncodingService;
}