com.vaadin.server.AbstractExtension Maven / Gradle / Ivy
/*
* Vaadin Framework 7
*
* Copyright (C) 2000-2024 Vaadin Ltd
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See for the full
* license.
*/
package com.vaadin.server;
/**
* An extension is an entity that is attached to a Component or another
* Extension and independently communicates between client and server.
*
* Extensions can use shared state and RPC in the same way as components.
*
* AbstractExtension adds a mechanism for adding the extension to any Connector
* (extend). To let the Extension determine what kind target it can be added to,
* the extend method is declared as protected.
*
* @author Vaadin Ltd
* @since 7.0.0
*/
public abstract class AbstractExtension extends AbstractClientConnector
implements Extension {
private boolean previouslyAttached = false;
private ClientConnector parent;
/**
* Creates a new extension instance without extending any connector.
*/
public AbstractExtension() {
// Empty default constructor
}
/**
* Creates a new extension instance that extends the provided connector.
*
* @since 7.4
*
* @param target
* the connector to extend
*/
public AbstractExtension(AbstractClientConnector target) {
this();
extend(target);
}
/**
* Gets a type that the parent must be an instance of. Override this if the
* extension only support certain targets, e.g. if only TextFields can be
* extended.
*
* @return a type that the parent must be an instance of
*/
protected Class extends ClientConnector> getSupportedParentType() {
return ClientConnector.class;
}
/**
* Add this extension to the target connector. This method is protected to
* allow subclasses to require a more specific type of target.
*
* @param target
* the connector to attach this extension to
*/
protected void extend(AbstractClientConnector target) {
target.addExtension(this);
}
@Override
public void remove() {
getParent().removeExtension(this);
}
@Override
public void setParent(ClientConnector parent) {
if (previouslyAttached && parent != null) {
throw new IllegalStateException(
"An extension can not be set to extend a new target after getting detached from the previous.");
}
Class extends ClientConnector> supportedParentType = getSupportedParentType();
if (parent == null || supportedParentType.isInstance(parent)) {
internalSetParent(parent);
previouslyAttached = true;
} else {
throw new IllegalArgumentException(getClass().getName()
+ " can only be attached to targets of type "
+ supportedParentType.getName() + " but attach to "
+ parent.getClass().getName() + " was attempted.");
}
}
/**
* Actually sets the parent and calls required listeners.
*
* @since 7.1
* @param parent
* The parent to set
*/
private void internalSetParent(ClientConnector parent) {
ClientConnector oldParent = getParent();
// Send a detach event if the component is currently attached
if (isAttached()) {
detach();
}
// Connect to new parent
this.parent = parent;
// Send attach event if the component is now attached
if (isAttached()) {
attach();
}
if (oldParent != null) {
oldParent.markAsDirty();
}
}
@Override
public ClientConnector getParent() {
return parent;
}
}