SharedTagContent { AbstractHtml addInnerHtml(final boolean updateClient, final AbstractHtml applicableTag, final ContentFormatter<T> formatter, final boolean subscribe) { final ContentFormatter<T> cFormatter = formatter != null ? formatter : DEFAULT_CONTENT_FORMATTER; final long stamp = lock.writeLock(); final AbstractHtml5SharedObject sharedObject = applicableTag .getSharedObject(); boolean listenerInvoked = false; NoTag noTagInserted = null; try { final Content<T> contentLocal = new Content<>(content, contentTypeHtml); NoTag noTag; try { final Content<String> formattedContent = cFormatter .format(contentLocal); if (formattedContent != null) { noTag = new NoTag(null, formattedContent.getContent(), formattedContent.isContentTypeHtml()); } else { noTag = new NoTag(null, "", false); } } catch (final RuntimeException e) { noTag = new NoTag(null, "", false); LOGGER.log(Level.SEVERE, "Exception while ContentFormatter.format", e); } final InnerHtmlListenerData listenerData = applicableTag .addInnerHtmlsAndGetEventsLockless(updateClient, noTag); noTagInserted = noTag; final InsertedTagData<T> insertedTagData = new InsertedTagData<>( ordinal, cFormatter, subscribe); ordinal++; insertedTags.put(noTag, insertedTagData); if (listenerData != null) { final ClientTasksWrapper clientTask = listenerData.listener() .innerHtmlsAdded(applicableTag, listenerData.events()); insertedTagData.lastClientTask(clientTask); listenerInvoked = true; } } finally { lock.unlockWrite(stamp); } if (listenerInvoked) { pushQueue(sharedObject); } return noTagInserted; } SharedTagContent(final T content);  SharedTagContent(final UpdateClientNature updateClientNature,
            final T content);  SharedTagContent(final T content, final boolean contentTypeHtml);  SharedTagContent(final UpdateClientNature updateClientNature,
            final T content, final boolean contentTypeHtml);  SharedTagContent(final boolean shared, final T content,
            final boolean contentTypeHtml);  SharedTagContent(final boolean shared, final T content); T getContent(); boolean isContentTypeHtml(); boolean isShared(); UpdateClientNature getUpdateClientNature(); void setUpdateClientNature(
            final UpdateClientNature updateClientNature); boolean isUpdateClient(); void setUpdateClient(final boolean updateClient); void setShared(final boolean shared); void setContent(final T content); void setContent(final UpdateClientNature updateClientNature,
            final T content); void setContent(final T content, final boolean contentTypeHtml); void setContent(final UpdateClientNature updateClientNature,
            final T content, final boolean contentTypeHtml); void setContent(final Set<AbstractHtml> exclusionTags,
            final T content); void setContent(final Set<AbstractHtml> exclusionTags,
            final T content, final boolean contentTypeHtml); void detach(final Set<AbstractHtml> exclusionTags); void detach(final boolean removeContent); void detach(final boolean removeContent,
            final Set<AbstractHtml> exclusionTags); void detach(final boolean removeContent,
            final Set<AbstractHtml> exclusionTags,
            final Set<AbstractHtml> exclusionClientUpdateTags); void addContentChangeListener(final AbstractHtml tag,
            final ContentChangeListener<T> contentChangeListener); void addDetachListener(final AbstractHtml tag,
            final DetachListener<T> detachListener); void removeContentChangeListener(
            final ContentChangeListener<T> contentChangeListener); void removeContentChangeListener(final AbstractHtml tag,
            final ContentChangeListener<T> contentChangeListener); void removeDetachListener(final DetachListener<T> detachListener); void removeDetachListener(final AbstractHtml tag,
            final DetachListener<T> detachListener); void removeContentChangeListeners(final AbstractHtml tag,
            final Collection<ContentChangeListener<T>> contentChangeListeners); void removeDetachListeners(final AbstractHtml tag,
            final Collection<DetachListener<T>> detachListeners); void removeAllContentChangeListeners(final AbstractHtml tag); void removeAllContentChangeListeners(); void removeAllDetachListeners(final AbstractHtml tag); void removeAllDetachListeners(); ContentFormatter<T> getContentFormatter(final AbstractHtml tag); Set<ContentChangeListener<T>> getContentChangeListeners(
            final AbstractHtml tag); Set<DetachListener<T>> getDetachListeners(final AbstractHtml tag);  }
@Test public void testAddInnerHtml() { { SharedTagContent<String> stc = new SharedTagContent<>(UpdateClientNature.SEQUENTIAL, "Test content", true); Div div = new Div(null); Span spanChild1 = new Span(div); spanChild1.addInnerHtml(stc); P pChild2 = new P(div); pChild2.addInnerHtml(stc); assertTrue(stc.isContentTypeHtml()); assertEquals("Test content", stc.getContent()); assertEquals("<div><span>Test content</span><p>Test content</p></div>", div.toHtmlString()); Div div2 = new Div(null); div2.addInnerHtml(stc); assertEquals("<div>Test content</div>", div2.toHtmlString()); stc.setContent(new HashSet<>(Arrays.asList(spanChild1)), "Content Changed", false); assertFalse(stc.isContentTypeHtml()); assertEquals(UpdateClientNature.SEQUENTIAL, stc.getUpdateClientNature()); assertEquals("Content Changed", stc.getContent()); assertEquals("<div><span>Content Changed</span><p>Content Changed</p></div>", div.toHtmlString()); assertEquals("<div>Content Changed</div>", div2.toHtmlString()); stc.setContent(new HashSet<>(Arrays.asList(spanChild1)), "Content Changed", true); assertTrue(stc.isContentTypeHtml()); assertEquals(UpdateClientNature.SEQUENTIAL, stc.getUpdateClientNature()); } }