You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2019/03/06 17:01:17 UTC
[isis] 01/01: ISIS-2102: Support for Server Side Events (SSE)
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch 2102_SSE
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 26cd14fd2c7439523b18d241205b268c987d020e
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Mar 6 18:01:04 2019 +0100
ISIS-2102: Support for Server Side Events (SSE)
extending the programming model with @Property(observe=...)
Task-Url: https://issues.apache.org/jira/browse/ISIS-2102
---
.../apache/isis/applib/annotation/Property.java | 11 ++++
.../isis/applib/events/sse/EventStream.java} | 34 ++++++----
.../isis/applib/events/sse/EventStreamSource.java | 70 ++++++++++++++++++++
.../org/apache/isis/applib/util/JaxbAdapters.java | 34 ++++++++++
.../facets/objectvalue/observe/ObserveFacet.java} | 19 +++---
.../objectvalue/observe/ObserveFacetAbstract.java | 61 ++++++++++++++++++
.../property/PropertyAnnotationFacetFactory.java | 20 +++++-
.../observe/ObserveFacetForPropertyAnnotation.java | 54 ++++++++++++++++
core/pom.xml | 2 +-
.../background/BackgroundServiceDefault.java | 5 +-
.../components/scalars/markup/MarkupComponent.java | 24 +++++--
.../scalars/markup/MarkupComponent_observing.java | 74 ++++++++++++++++++++++
.../ui/components/scalars/markup/MarkupPanel.java | 27 ++++++--
.../scalars/markup/ObservingComponent.js | 23 +++++++
.../scalars/markup/StandaloneMarkupPanel.java | 2 +-
.../wicket/ui/errors/ExceptionStackTracePanel.java | 2 +-
16 files changed, 422 insertions(+), 40 deletions(-)
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
index 51591a7..7ff3e08 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
@@ -30,6 +30,7 @@ import javax.jdo.annotations.NotPersistent;
import org.apache.isis.applib.conmap.ContentMappingServiceForCommandDto;
import org.apache.isis.applib.conmap.ContentMappingServiceForCommandsDto;
import org.apache.isis.applib.events.domain.PropertyDomainEvent;
+import org.apache.isis.applib.events.sse.EventStreamSource;
import org.apache.isis.applib.services.command.CommandDtoProcessor;
import org.apache.isis.applib.services.command.CommandWithDto;
import org.apache.isis.applib.services.command.spi.CommandService;
@@ -253,5 +254,15 @@ public @interface Property {
* @see <a href="http://www.w3schools.com/tags/att_input_accept.asp">http://www.w3schools.com</a>
*/
String fileAccept() default "";
+
+
+
+
+
+ /**
+ * TODO
+ *
+ */
+ Class<? extends EventStreamSource> observe() default EventStreamSource.Nop.class;
}
\ No newline at end of file
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java b/core/applib/src/main/java/org/apache/isis/applib/events/sse/EventStream.java
similarity index 59%
copy from core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java
copy to core/applib/src/main/java/org/apache/isis/applib/events/sse/EventStream.java
index 60d665d..59be17a 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/events/sse/EventStream.java
@@ -17,19 +17,31 @@
* under the License.
*/
-package org.apache.isis.viewer.wicket.ui.components.scalars.markup;
+package org.apache.isis.applib.events.sse;
-import org.apache.isis.viewer.wicket.model.models.ValueModel;
-import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+import java.util.UUID;
+import java.util.function.Predicate;
-public class StandaloneMarkupPanel extends PanelAbstract<ValueModel> {
-
- private static final long serialVersionUID = 1L;
- private static final String ID_STANDALONE_VALUE = "standaloneValue";
+/**
+ * Server-side events.
+ *
+ * @see https://www.w3schools.com/html/html5_serversentevents.asp
+ *
+ * @since 2.0.0-M3
+ *
+ */
+public interface EventStream {
- public StandaloneMarkupPanel(final String id, final ValueModel valueModel) {
- super(id, valueModel);
- add(new MarkupComponent(ID_STANDALONE_VALUE, getModel()));
- }
+ UUID getId();
+ Class<?> getSourceType();
+ void listenWhile(Predicate<EventStreamSource> listener);
+
+ void fire(EventStreamSource source);
+
+ void close();
+
+ void awaitClose() throws InterruptedException;
+
+
}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/events/sse/EventStreamSource.java b/core/applib/src/main/java/org/apache/isis/applib/events/sse/EventStreamSource.java
new file mode 100644
index 0000000..df58373
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/events/sse/EventStreamSource.java
@@ -0,0 +1,70 @@
+/*
+ * 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.applib.events.sse;
+
+import org.apache.isis.applib.value.Markup;
+
+/**
+ * Server-side events.
+ *
+ * @see https://www.w3schools.com/html/html5_serversentevents.asp
+ *
+ * @since 2.0.0-M3
+ *
+ */
+public interface EventStreamSource {
+
+ void run(EventStream eventStream);
+
+ Markup getPayload();
+
+ // -- PROPERTY ANNOTATION DEFAULT
+
+ /**
+ * This class is the default for the
+ * {@link org.apache.isis.applib.annotation.Property#observe()} annotation attribute.
+ */
+ public static final class Nop implements EventStreamSource {
+
+ @Override
+ public void run(EventStream eventStream) {
+ // just do nothing
+ }
+
+ @Override
+ public Markup getPayload() {
+ return new Markup();
+ }
+
+ }
+
+ // -- BASIC PREDICATES
+
+ public static boolean isObservable(Class<?> type) {
+ if(type==null) {
+ return false;
+ }
+ if(!EventStreamSource.class.isAssignableFrom(type)) {
+ return false;
+ }
+ return !type.equals(Nop.class);
+ }
+
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/util/JaxbAdapters.java b/core/applib/src/main/java/org/apache/isis/applib/util/JaxbAdapters.java
index ace6f9c..8a81955 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/util/JaxbAdapters.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/util/JaxbAdapters.java
@@ -18,12 +18,17 @@
*/
package org.apache.isis.applib.util;
+import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
+import java.util.Base64;
import javax.xml.bind.annotation.adapters.XmlAdapter;
+import org.apache.isis.applib.value.Markup;
+import org.apache.isis.commons.internal.base._Strings;
+
/**
* Provides JAXB XmlAdapters for Java built-in temporal types.
* Others types might be added, if convenient.
@@ -39,6 +44,35 @@ import javax.xml.bind.annotation.adapters.XmlAdapter;
*/
public final class JaxbAdapters {
+ // -- MARKUP
+
+ public static final class MarkupAdapter extends XmlAdapter<String, Markup>{
+
+ private final static Base64.Encoder encoder = Base64.getEncoder();
+ private final static Base64.Decoder decoder = Base64.getDecoder();
+
+ @Override
+ public Markup unmarshal(String v) throws Exception {
+ if(v==null) {
+ return null;
+ }
+ final String html = _Strings.ofBytes(decoder.decode(v), StandardCharsets.UTF_8);
+ return new Markup(html);
+ }
+
+ @Override
+ public String marshal(Markup v) throws Exception {
+ if(v==null) {
+ return null;
+ }
+ final String html = v.asString();
+ return encoder.encodeToString(_Strings.toBytes(html, StandardCharsets.UTF_8));
+ }
+
+ }
+
+ // -- TEMPORAL VALUE TYPES
+
public static final class DateAdapter extends XmlAdapter<String, java.util.Date>{
public java.util.Date unmarshal(String v) throws Exception {
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/observe/ObserveFacet.java
similarity index 59%
copy from core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java
copy to core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/observe/ObserveFacet.java
index 60d665d..078bcb1 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/observe/ObserveFacet.java
@@ -17,19 +17,16 @@
* under the License.
*/
-package org.apache.isis.viewer.wicket.ui.components.scalars.markup;
+package org.apache.isis.core.metamodel.facets.objectvalue.observe;
-import org.apache.isis.viewer.wicket.model.models.ValueModel;
-import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+import org.apache.isis.applib.events.sse.EventStreamSource;
+import org.apache.isis.core.metamodel.facets.SingleClassValueFacet;
-public class StandaloneMarkupPanel extends PanelAbstract<ValueModel> {
-
- private static final long serialVersionUID = 1L;
- private static final String ID_STANDALONE_VALUE = "standaloneValue";
+/**
+ * Corresponds to <tt>@Property(observe=...)</tt> annotation in the Isis programming model.
+ */
+public interface ObserveFacet extends SingleClassValueFacet {
- public StandaloneMarkupPanel(final String id, final ValueModel valueModel) {
- super(id, valueModel);
- add(new MarkupComponent(ID_STANDALONE_VALUE, getModel()));
- }
+ Class<? extends EventStreamSource> getEventStreamType();
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/observe/ObserveFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/observe/ObserveFacetAbstract.java
new file mode 100644
index 0000000..2762f0f
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/observe/ObserveFacetAbstract.java
@@ -0,0 +1,61 @@
+/*
+ * 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.metamodel.facets.objectvalue.observe;
+
+import org.apache.isis.applib.events.sse.EventStreamSource;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.SingleClassValueFacetAbstract;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+public abstract class ObserveFacetAbstract extends SingleClassValueFacetAbstract implements ObserveFacet {
+
+ private Class<? extends EventStreamSource> eventStreamType;
+
+ public static Class<? extends Facet> type() {
+ return ObserveFacet.class;
+ }
+
+ public ObserveFacetAbstract(
+ final Class<? extends EventStreamSource> eventStreamType,
+ final FacetHolder holder) {
+
+ super(type(), holder, eventStreamType, null);
+ this.eventStreamType = eventStreamType;
+ }
+
+ @Override
+ public Class<?> value() {
+ return eventStreamType;
+ }
+
+ @Override
+ public Class<? extends EventStreamSource> getEventStreamType() {
+ return eventStreamType;
+ }
+
+ @Override
+ public ObjectSpecification valueSpec() {
+ throw _Exceptions.notImplemented();
+ }
+
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
index 4e40191..898de3c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
@@ -43,6 +43,7 @@ import org.apache.isis.core.metamodel.facets.object.domainobject.domainevents.Pr
import org.apache.isis.core.metamodel.facets.objectvalue.fileaccept.FileAcceptFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxLengthFacet;
+import org.apache.isis.core.metamodel.facets.objectvalue.observe.ObserveFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.regex.RegExFacet;
import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
import org.apache.isis.core.metamodel.facets.propcoll.notpersisted.NotPersistedFacet;
@@ -64,6 +65,7 @@ import org.apache.isis.core.metamodel.facets.properties.property.modify.Property
import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertySetterFacetForDomainEventFromPropertyAnnotation;
import org.apache.isis.core.metamodel.facets.properties.property.mustsatisfy.MustSatisfySpecificationFacetForPropertyAnnotation;
import org.apache.isis.core.metamodel.facets.properties.property.notpersisted.NotPersistedFacetForPropertyAnnotation;
+import org.apache.isis.core.metamodel.facets.properties.property.observe.ObserveFacetForPropertyAnnotation;
import org.apache.isis.core.metamodel.facets.properties.property.publishing.PublishedPropertyFacetForPropertyAnnotation;
import org.apache.isis.core.metamodel.facets.properties.property.regex.RegExFacetForPatternAnnotationOnProperty;
import org.apache.isis.core.metamodel.facets.properties.property.regex.RegExFacetForPropertyAnnotation;
@@ -75,9 +77,11 @@ import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorCom
import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForConflictingOptionality;
import org.apache.isis.core.metamodel.util.EventUtil;
-public class PropertyAnnotationFacetFactory extends FacetFactoryAbstract implements MetaModelValidatorRefiner {
+public class PropertyAnnotationFacetFactory extends FacetFactoryAbstract
+implements MetaModelValidatorRefiner {
- private final MetaModelValidatorForConflictingOptionality conflictingOptionalityValidator = new MetaModelValidatorForConflictingOptionality();
+ private final MetaModelValidatorForConflictingOptionality conflictingOptionalityValidator =
+ new MetaModelValidatorForConflictingOptionality();
public PropertyAnnotationFacetFactory() {
@@ -98,6 +102,7 @@ public class PropertyAnnotationFacetFactory extends FacetFactoryAbstract impleme
processOptional(processMethodContext);
processRegEx(processMethodContext);
processFileAccept(processMethodContext);
+ processObserve(processMethodContext);
}
@@ -370,6 +375,17 @@ public class PropertyAnnotationFacetFactory extends FacetFactoryAbstract impleme
FacetUtil.addFacet(facet);
}
+
+ void processObserve(final ProcessMethodContext processMethodContext) {
+ final Method method = processMethodContext.getMethod();
+ final FacetHolder holder = processMethodContext.getFacetHolder();
+
+ // else search for @Property(observe=...)
+ final List<Property> properties = Annotations.getAnnotations(method, Property.class);
+ ObserveFacet facet = ObserveFacetForPropertyAnnotation.create(properties, holder);
+
+ FacetUtil.addFacet(facet);
+ }
// //////////////////////////////////////
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/observe/ObserveFacetForPropertyAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/observe/ObserveFacetForPropertyAnnotation.java
new file mode 100644
index 0000000..c23a4af
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/observe/ObserveFacetForPropertyAnnotation.java
@@ -0,0 +1,54 @@
+/*
+ * 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.metamodel.facets.properties.property.observe;
+
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.events.sse.EventStreamSource;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.objectvalue.observe.ObserveFacet;
+import org.apache.isis.core.metamodel.facets.objectvalue.observe.ObserveFacetAbstract;
+
+public class ObserveFacetForPropertyAnnotation extends ObserveFacetAbstract {
+
+ public static ObserveFacet create(
+ final List<Property> properties,
+ final FacetHolder holder) {
+
+ return properties.stream()
+ .map(Property::observe)
+ .peek(x->System.out.println("..."+x))
+ .filter(EventStreamSource::isObservable)
+ .findFirst()
+ .map(eventStreamType -> new ObserveFacetForPropertyAnnotation(
+ eventStreamType, holder))
+ .orElse(null);
+ }
+
+ private ObserveFacetForPropertyAnnotation(
+ Class<? extends EventStreamSource> eventStreamType,
+ FacetHolder holder) {
+
+ super(eventStreamType, holder);
+ }
+
+
+}
diff --git a/core/pom.xml b/core/pom.xml
index 702ac6b..efa89ac 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -174,7 +174,7 @@
<picocontainer.version>2.15</picocontainer.version>
- <javaee.version>7.0</javaee.version>
+ <javaee.version>8.0</javaee.version>
<htmlparser.version>2.1</htmlparser.version>
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
index ed6d905..ad885fd 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
@@ -16,10 +16,7 @@
*/
package org.apache.isis.core.runtime.services.background;
-import static org.apache.isis.commons.internal.base._Casts.uncheckedCast;
-
import java.lang.reflect.InvocationHandler;
-import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -46,6 +43,8 @@ import org.apache.isis.core.metamodel.specloader.classsubstitutor.ProxyEnhanced;
import org.apache.isis.core.plugins.codegen.ProxyFactory;
import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
+import static org.apache.isis.commons.internal.base._Casts.uncheckedCast;
+
/**
* For command-reification depends on an implementation of
* {@link org.apache.isis.applib.services.background.BackgroundCommandService} to
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupComponent.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupComponent.java
index f3b4bfa..b8ae03c 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupComponent.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupComponent.java
@@ -19,25 +19,39 @@
package org.apache.isis.viewer.wicket.ui.components.scalars.markup;
-import org.apache.isis.applib.value.Markup;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.WebComponent;
import org.apache.wicket.markup.parser.XmlTag.TagType;
import org.apache.wicket.model.IModel;
+import org.apache.isis.applib.value.LocalResourcePath;
+import org.apache.isis.applib.value.Markup;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+
public class MarkupComponent extends WebComponent {
private static final long serialVersionUID = 1L;
+
+ private final LocalResourcePath observing;
- public MarkupComponent(final String id, IModel<?> model){
+ public MarkupComponent(final String id, IModel<?> model, LocalResourcePath observing){
super(id, model);
+ this.observing = observing;
}
@Override
public void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag){
- replaceComponentTagBody(markupStream, openTag, extractHtmlOrElse(getDefaultModelObject(), ""));
+ final CharSequence htmlContent = extractHtmlOrElse(getDefaultModelObject(), "" /*fallback*/);
+ replaceComponentTagBody(
+ markupStream,
+ openTag,
+
+ observing!=null
+ ? MarkupComponent_observing.decorate(htmlContent, observing)
+ : htmlContent
+
+ );
}
@Override
@@ -72,4 +86,6 @@ public class MarkupComponent extends WebComponent {
return modelObject.toString();
}
+
+
}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupComponent_observing.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupComponent_observing.java
new file mode 100644
index 0000000..773de2d
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupComponent_observing.java
@@ -0,0 +1,74 @@
+/*
+ * 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.viewer.wicket.ui.components.scalars.markup;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+import org.apache.isis.applib.value.LocalResourcePath;
+import org.apache.isis.commons.internal.resources._Resources;
+
+import static org.apache.isis.commons.internal.base._Strings.isNullOrEmpty;
+
+final class MarkupComponent_observing {
+
+ private static final String jScriptTemplateResource = "ObservingComponent.js";
+
+ static CharSequence decorate(CharSequence htmlContent, LocalResourcePath observing) {
+ if(observing==null) {
+ return htmlContent;
+ }
+ final String jScriptTemplate;
+ try {
+ jScriptTemplate = _Resources.loadAsString(
+ MarkupComponent_observing.class, jScriptTemplateResource, StandardCharsets.UTF_8);
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ return resourceNotFound();
+ }
+
+ if(isNullOrEmpty(jScriptTemplate)) {
+ return resourceNotFound();
+ }
+
+ final String targetId = UUID.randomUUID().toString();
+ final String observingPath = _Resources.prependContextPathIfPresent(observing.getPath());
+
+ final StringBuilder sb = new StringBuilder();
+ sb
+ .append("<div id=\"").append(targetId).append("\">\n")
+ .append(htmlContent)
+ .append("\n</div>\n")
+ .append("<script type=\"text/javascript\">\n")
+ .append(jScriptTemplate
+ .replace("${targetId}", targetId)
+ .replace("${observing}", observingPath))
+ .append("\n</script>\n");
+
+ return sb.toString();
+ }
+
+ private static String resourceNotFound() {
+ return "Template resource not found: '"+jScriptTemplateResource+"'.";
+ }
+
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupPanel.java
index f6e9ffd..133b345 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupPanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupPanel.java
@@ -19,14 +19,17 @@
package org.apache.isis.viewer.wicket.ui.components.scalars.markup;
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
-import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldParseableAbstract;
-import org.apache.isis.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.model.Model;
+import org.apache.isis.applib.value.LocalResourcePath;
+import org.apache.isis.core.metamodel.facets.objectvalue.observe.ObserveFacet;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldParseableAbstract;
+import org.apache.isis.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
+
/**
* Panel for rendering scalars of type {@link org.apache.isis.applib.value.Markup}.
*/
@@ -50,8 +53,9 @@ public class MarkupPanel extends ScalarPanelTextFieldParseableAbstract {
// fallback to text editor
return super.createScalarIfRegularFormGroup();
}
-
- final MarkupComponent markupComponent = createMarkupComponent("scalarValueContainer");
+
+ final MarkupComponent markupComponent =
+ createMarkupComponent("scalarValueContainer");
getTextField().setLabel(Model.of(getModel().getName()));
@@ -74,9 +78,20 @@ public class MarkupPanel extends ScalarPanelTextFieldParseableAbstract {
// -- HELPER
private MarkupComponent createMarkupComponent(String id) {
- MarkupComponent markupComponent = new MarkupComponent(id, getModel());
+ MarkupComponent markupComponent = new MarkupComponent(id, getModel(), getEventStreamResource());
markupComponent.setEnabled(false);
return markupComponent;
}
+
+ private LocalResourcePath getEventStreamResource() {
+ final ObserveFacet observeFacet = super.scalarModel.getFacet(ObserveFacet.class);
+ if(observeFacet==null) {
+ return null;
+ }
+ final String eventStreamId = observeFacet.getEventStreamType().getName();
+ final LocalResourcePath ssePath = new LocalResourcePath("/sse?eventStream=" + eventStreamId);
+ return ssePath;
+ }
+
}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/ObservingComponent.js b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/ObservingComponent.js
new file mode 100644
index 0000000..f46b00b
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/ObservingComponent.js
@@ -0,0 +1,23 @@
+var sse_observe = function(targetId, observing) {
+
+ function updateField(newValue) {
+ document.getElementById(targetId).innerHTML = newValue;
+ }
+
+ function isEventSourceSupported() {
+ return typeof(EventSource) !== "undefined";
+ }
+
+ if(isEventSourceSupported()) {
+ var source = new EventSource(observing);
+ source.onmessage = function(event) {
+ var decodedData = window.atob(event.data);
+ updateField(decodedData);
+ };
+ } else {
+ updateField("Sorry, your browser does not support server-sent events.");
+ }
+
+}
+
+sse_observe("${targetId}", "${observing}");
\ No newline at end of file
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java
index 60d665d..913df13 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/StandaloneMarkupPanel.java
@@ -29,7 +29,7 @@ public class StandaloneMarkupPanel extends PanelAbstract<ValueModel> {
public StandaloneMarkupPanel(final String id, final ValueModel valueModel) {
super(id, valueModel);
- add(new MarkupComponent(ID_STANDALONE_VALUE, getModel()));
+ add(new MarkupComponent(ID_STANDALONE_VALUE, getModel(), null /*observing*/));
}
}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
index c77f601..2d07567 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
@@ -98,7 +98,7 @@ public class ExceptionStackTracePanel extends Panel {
if(ticketMarkup == null) {
Components.permanentlyHide(this, ID_TICKET_MARKUP);
} else {
- add(new MarkupComponent(ID_TICKET_MARKUP, Model.of(ticket.getMarkup())));
+ add(new MarkupComponent(ID_TICKET_MARKUP, Model.of(ticket.getMarkup()), null /*observing*/));
}
final boolean suppressExceptionDetail =