All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fujion.component.Page Maven / Gradle / Ivy

There is a newer version: 3.1.0
Show newest version
/*
 * #%L
 * fujion
 * %%
 * Copyright (C) 2008 - 2017 Regenstrief Institute, Inc.
 * %%
 * Licensed 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.
 *
 * #L%
 */
package org.fujion.component;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.fujion.ancillary.ComponentException;
import org.fujion.ancillary.INamespace;
import org.fujion.annotation.Component;
import org.fujion.annotation.Component.ChildTag;
import org.fujion.annotation.Component.ContentHandling;
import org.fujion.annotation.Component.PropertyGetter;
import org.fujion.annotation.Component.PropertySetter;
import org.fujion.client.ClientRequest;
import org.fujion.client.Synchronizer;
import org.fujion.common.WeakMap;
import org.fujion.core.WebUtil;
import org.fujion.event.Event;
import org.fujion.event.EventQueue;
import org.fujion.page.PageRegistry;
import org.fujion.websocket.Session;

/**
 * This is the root component of a Fujion Server Page.
 */
@Component(tag = "page", widgetClass = "Page", content = ContentHandling.AS_CHILD, childTag = @ChildTag("*"))
public final class Page extends BaseComponent implements INamespace {

    public static final String ID_PREFIX = "_fujion_";

    private static final AtomicInteger uniqueId = new AtomicInteger();

    private Synchronizer synchronizer;

    private Session session;

    private int nextId;

    private final Map ids = new WeakMap<>();

    private final EventQueue eventQueue = new EventQueue(this);

    private final Map browserInfo = new HashMap<>();

    private Map queryParams;

    private String title;

    private final String src;

    /**
     * Creates an uninitialized page. For internal use only.
     *
     * @param src URL of a FSP resource that will be used to populate the page upon initialization.
     * @return The newly created page.
     */
    public static Page _create(String src) {
        return new Page(src);
    }

    /**
     * Performs final initialization of a newly created page. For internal use only.
     *
     * @param page The page to initialize.
     * @param request The initialization request from the client.
     * @param synchronizer The synchronizer that the page will use.
     */
    @SuppressWarnings("unchecked")
    public static void _init(Page page, ClientRequest request, Synchronizer synchronizer) {
        page.synchronizer = synchronizer;
        page.session = request.getSession();
        page.browserInfo.putAll((Map) request.getData());
        page._attach(page);
    }

    public Page() {
        src = null;
    }

    private Page(String src) {
        this._setId(ID_PREFIX + Integer.toHexString(uniqueId.incrementAndGet()));
        this.src = src;
        PageRegistry.registerPage(this);
    }

    /**
     * Returns the synchronizer for this page.
     *
     * @return The page's synchronizer.
     */
    public Synchronizer getSynchronizer() {
        return synchronizer;
    }

    /**
     * Returns the event queue for this page. Events placed on the event queue (typically by posting
     * the event) will be processed at the end of the execution cycle.
     *
     * @return The event queue.
     */
    public EventQueue getEventQueue() {
        return eventQueue;
    }

    /**
     * A Page may not have a parent.
     *
     * @exception ComponentException Always thrown.
     * @see org.fujion.component.BaseComponent#setParent(org.fujion.component.BaseComponent)
     */
    @Override
    public void setParent(BaseComponent parent) {
        throw new ComponentException(this, "Page cannot have a parent.");
    }

    /**
     * Returns the requested attribute value from information provided by the client browser.
     *
     * @param key The attribute key.
     * @return The attribute value as a string, possibly null.
     */
    public String getBrowserInfo(String key) {
        Object value = browserInfo.get(key);
        return value == null ? null : value.toString();
    }

    /**
     * Returns the requested attribute value, cast to the specified type, from information provided
     * by the client browser.
     *
     * @param  The expected return type.
     * @param key The attribute key.
     * @param type The expected return type.
     * @return The attribute value, possibly null.
     */
    @SuppressWarnings("unchecked")
    public  T getBrowserInfo(String key, Class type) {
        return (T) browserInfo.get(key);
    }

    /**
     * Returns an immutable map of information provided by the browser.
     *
     * @return An immutable map of information provided by the browser.
     */
    public Map getBrowserInfo() {
        return Collections.unmodifiableMap(browserInfo);
    }

    /**
     * Returns the named query parameter from the original request URL.
     *
     * @param param Name of query parameter.
     * @return The value of the query parameter, or null if not found.
     */
    public String getQueryParam(String param) {
        return getQueryParams().get(param);
    }

    /**
     * Returns an immutable map containing all query parameters from the original request URL.
     *
     * @return An immutable map containing all query parameters from the original request URL.
     */
    public Map getQueryParams() {
        if (queryParams == null) {
            String requestUrl = (String) browserInfo.get("requestURL");
            int i = requestUrl == null ? -1 : requestUrl.indexOf("?");

            if (i >= 0) {
                queryParams = WebUtil.queryStringToMap(requestUrl.substring(i + 1), ",");
            } else {
                queryParams = Collections.emptyMap();
            }
        }

        return Collections.unmodifiableMap(queryParams);
    }

    /**
     * Returns the web socket session dedicated to this page.
     *
     * @return The web socket session dedicated to this page.
     */
    public Session getSession() {
        return session;
    }

    /**
     * Returns the URL of the FSP resource that created this page.
     *
     * @return The URL of the FSP resource that created this page.
     */
    public String getSrc() {
        return src;
    }

    /**
     * Returns the next available component id.
     *
     * @return The next available component id.
     */
    private String nextComponentId() {
        return getId() + "_" + Integer.toHexString(++nextId);
    }

    /**
     * Cleanup page resources.
     * 
     * @see org.fujion.component.BaseComponent#onDestroy()
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        PageRegistry.unregisterPage(this);
        synchronizer.clear();
        eventQueue.clearAll();
        session = null;
    }

    /**
     * Registers/unregisters a component newly attached to this page.
     *
     * @param component Component to register/unregister.
     * @param register If true, register the component. If false, unregister it.
     */
    /*package*/ void registerComponent(BaseComponent component, boolean register) {
        String id = component.getId();

        if (id == null) {
            id = nextComponentId();
            component._setId(id);
        }

        if (register) {
            ids.put(id, component);
        } else {
            ids.remove(id);
        }

        Event event = new Event(register ? "register" : "unregister", this, component);
        fireEvent(event);
    }

    /**
     * Searches for a component attached to this page given its id.
     *
     * @param id Identifier of the component sought.
     * @return The component with the specified id, or null if not found.
     */
    public BaseComponent findById(String id) {
        int i = id.indexOf('-');
        return ids.get(i == -1 ? id : id.substring(0, i));
    }

    /**
     * Returns the page title.
     *
     * @return The page title.
     */
    @PropertyGetter("title")
    public String getTitle() {
        return title;
    }

    /**
     * Sets the page title.
     *
     * @param title The page title.
     */
    @PropertySetter("title")
    public void setTitle(String title) {
        if (!areEqual(title = nullify(title), this.title)) {
            sync("title", this.title = title);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy