001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.ajax;
018
019import java.time.Duration;
020import org.apache.wicket.Component;
021import org.apache.wicket.Session;
022import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
023import org.apache.wicket.markup.head.IHeaderResponse;
024import org.apache.wicket.markup.head.JavaScriptHeaderItem;
025import org.apache.wicket.markup.html.pages.BrowserInfoForm;
026import org.apache.wicket.protocol.http.request.WebClientInfo;
027import org.apache.wicket.request.IRequestParameters;
028import org.apache.wicket.request.cycle.RequestCycle;
029import org.apache.wicket.util.lang.Args;
030import org.danekja.java.util.function.serializable.SerializableBiConsumer;
031
032/**
033 * An behavior that collects the information to populate
034 * WebClientInfo's ClientProperties by using Ajax
035 *
036 * @see #onClientInfo(AjaxRequestTarget, org.apache.wicket.protocol.http.request.WebClientInfo)
037 */
038public class AjaxClientInfoBehavior extends AbstractAjaxTimerBehavior
039{
040        private static final long serialVersionUID = 1L;
041
042        /**
043         * Constructor.
044         *
045         * Auto fires after 50 millis.
046         */
047        public AjaxClientInfoBehavior()
048        {
049                this(Duration.ofMillis(50));
050        }
051
052        /**
053         * Constructor. Auto fires after {@code duration}.
054         * 
055         * @param duration the duration of the client info behavior
056         */
057        public AjaxClientInfoBehavior(Duration duration)
058        {
059                super(duration);
060        }
061
062        @Override
063        protected final void onTimer(AjaxRequestTarget target)
064        {
065                stop(target);
066
067                RequestCycle requestCycle = RequestCycle.get();
068
069                IRequestParameters requestParameters = requestCycle.getRequest().getRequestParameters();
070                WebClientInfo clientInfo = newWebClientInfo(requestCycle);
071                clientInfo.getProperties().read(requestParameters);
072                Session.get().setClientInfo(clientInfo);
073
074                onClientInfo(target, clientInfo);
075        }
076
077        protected WebClientInfo newWebClientInfo(RequestCycle requestCycle)
078        {
079                return new WebClientInfo(requestCycle);
080        }
081
082        /**
083         * A callback method invoked when the client info is collected.
084         * 
085         * @param target
086         *          The Ajax request handler
087         * @param clientInfo
088         *          The collected info for the client 
089         */
090        protected void onClientInfo(AjaxRequestTarget target, WebClientInfo clientInfo)
091        {
092        }
093
094        @Override
095        protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
096        {
097                super.updateAjaxAttributes(attributes);
098
099                attributes.getDynamicExtraParameters().add("return Wicket.BrowserInfo.collect()");
100        }
101
102        @Override
103        public void renderHead(Component component, IHeaderResponse response)
104        {
105                super.renderHead(component, response);
106
107                response.render(JavaScriptHeaderItem.forReference(BrowserInfoForm.JS));
108        }
109
110        /**
111         * Creates an {@link AjaxClientInfoBehavior} based on lambda expressions
112         *
113         * @param onClientInfo
114         *            the {@code SerializableBiConsumer} which accepts the {@link AjaxRequestTarget} and the
115         *            {@link WebClientInfo}
116         * @return the {@link AjaxClientInfoBehavior}
117         */
118        public static AjaxClientInfoBehavior onClientInfo(SerializableBiConsumer<AjaxRequestTarget, WebClientInfo> onClientInfo)
119        {
120                Args.notNull(onClientInfo, "onClientInfo");
121
122                return new AjaxClientInfoBehavior()
123                {
124
125                        private static final long serialVersionUID = 1L;
126
127                        @Override
128                        protected void onClientInfo(AjaxRequestTarget target, WebClientInfo clientInfo)
129                        {
130                                onClientInfo.accept(target, clientInfo);
131                        }
132                };
133        }
134}