Package at.molindo.notify.servlet

Source Code of at.molindo.notify.servlet.NotifyFilterBean

/**
* Copyright 2010 Molindo GmbH
*
* 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.
*/

package at.molindo.notify.servlet;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.filter.GenericFilterBean;

import at.molindo.notify.INotifyService.NotifyException;
import at.molindo.notify.channel.IPullChannel;
import at.molindo.notify.channel.IPullChannel.PullException;
import at.molindo.notify.confirm.IConfirmationService;
import at.molindo.notify.confirm.IConfirmationService.ConfirmationException;
import at.molindo.notify.model.Confirmation;
import at.molindo.notify.model.IChannelPreferences;
import at.molindo.notify.model.IParams;
import at.molindo.notify.model.IRequestConfigurable;
import at.molindo.notify.model.Notification.Type;
import at.molindo.notify.model.ParamValue;
import at.molindo.notify.model.Params;
import at.molindo.utils.data.StringUtils;
import at.molindo.utils.io.CharsetUtils;

public class NotifyFilterBean extends GenericFilterBean implements INotifyUrlFactory {

  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NotifyFilterBean.class);

  static final String PARAMTER_BASE_URL_PROPERTY = "baseUrlProperty";
  static final String PARAMTER_BASE_URL = "baseUrl";

  static final String DEFAULT_MOUNT_PATH = "notify";
  static final String PARAMTER_MOUNT_PATH = "mountPath";

  static final String DEFAULT_PULL_PREFIX = "pull";
  static final String PARAMTER_PULL_PREFIX = "pullPrefix";

  static final String DEFAULT_CONFIRM_PREFIX = "confirm";
  static final String PARAMTER_CONFIRM_PREFIX = "confirmPrefix";

  private String _baseUrl;
  private String _baseUrlProperty;

  private String _mountPath;

  private String _pullPrefix;
  private Pattern _pullPattern;

  private String _confirmPrefix;
  private Pattern _confirmPattern;

  private final Map<String, IPullChannel> _channels = new HashMap<String, IPullChannel>();
  private IConfirmationService _confirmationService;

  @Override
  public void initFilterBean() throws ServletException {
    {
      if (!StringUtils.empty(_baseUrlProperty)) {
        String baseUrl = System.getProperty(_baseUrlProperty);
        if (!StringUtils.empty(baseUrl)) {
          _baseUrl = baseUrl;
        }
      }

      if (StringUtils.empty(_baseUrl)) {
        throw new ServletException(String.format("parameter %s is required", PARAMTER_BASE_URL));
      }

      try {
        _baseUrl = StringUtils.stripTrailing(new URL(_baseUrl).toString(), "/");
      } catch (MalformedURLException e) {
        throw new ServletException(String.format("illegal value for parameter %s: '%s'", PARAMTER_BASE_URL,
            _baseUrl), e);
      }
    }

    {
      if (StringUtils.empty(_mountPath)) {
        _mountPath = DEFAULT_MOUNT_PATH;
      }
      _mountPath = StringUtils.stripTrailing(StringUtils.startWith(_mountPath, "/"), "/");
    }

    {
      if (StringUtils.empty(_pullPrefix)) {
        _pullPrefix = DEFAULT_PULL_PREFIX;
      }
      _pullPrefix = StringUtils.endWith(StringUtils.startWith(_pullPrefix, "/"), "/");
      _pullPattern = Pattern.compile("^" + Pattern.quote(_pullPrefix) + "([^/?]+)/([^/?]+).*$");
    }

    {
      if (StringUtils.empty(_confirmPrefix)) {
        _confirmPrefix = DEFAULT_CONFIRM_PREFIX;
      }
      _confirmPrefix = StringUtils.endWith(StringUtils.startWith(_confirmPrefix, "/"), "/");
      _confirmPattern = Pattern.compile("^" + Pattern.quote(_confirmPrefix) + "([^/?]+)/?$");
    }
  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
      ServletException {
    doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
  }

  public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException {

    String path = request.getRequestURI();
    if (StringUtils.empty(path) || !path.startsWith(_mountPath)) {
      response.sendError(404);
      return;
    }
    path = path.substring(_mountPath.length());

    if (path.startsWith(_pullPrefix)) {
      pull(request, response, path);
    } else if (path.startsWith(_confirmPrefix)) {
      if (!confirm(request, response, path)) {
        chain.doFilter(request, response);
      }
    } else {
      chain.doFilter(request, response);
    }
  }

  protected void pull(HttpServletRequest request, HttpServletResponse response, String path) throws IOException {
    Matcher m = _pullPattern.matcher(path);
    if (!m.matches()) {
      response.sendError(404);
      return;
    }

    String channelId = decode(m.group(1));
    String userId = decode(m.group(2));

    if (StringUtils.empty(userId) || StringUtils.empty(channelId)) {
      response.sendError(404);
      return;
    }

    IPullChannel channel = getChannel(channelId);
    if (channel == null) {
      response.sendError(404);
      return;
    }

    IChannelPreferences prefs = channel.newDefaultPreferences();
    if (prefs instanceof IRequestConfigurable) {
      try {
        Map<?, ?> queryParams = request.getParameterMap();

        for (Map.Entry<?, ?> e : queryParams.entrySet()) {
          Object value = e.getValue();
          if (value != null && value.getClass().isArray()) {
            String[] vals = (String[]) value;
            value = vals.length > 0 ? vals[0] : null;
          }
          ((IRequestConfigurable) prefs).setParam((String) e.getKey(), (String) value);
        }
      } catch (NotifyException e) {
        response.sendError(404);
        return;
      }
    }

    if (channel.getNotificationTypes().contains(Type.PRIVATE) && !channel.isAuthorized(userId, prefs)) {
      response.sendError(403);
    } else if (channel.isConfigured(new Params(prefs.getParams()))) {
      try {
        String output = channel.pull(userId, prefs);
        if (StringUtils.empty(output)) {
          response.sendError(404);
        } else {
          response.getWriter().write(output);
        }
      } catch (PullException e) {
        log.info("failed to pull notifications", e);
        response.sendError(500);
      }
    } else {
      response.sendError(404);
    }
  }

  protected boolean confirm(HttpServletRequest request, HttpServletResponse response, String path)
      throws IOException, ServletException {
    Matcher m = _confirmPattern.matcher(path);
    if (!m.matches()) {
      return false;
    }

    String key = decode(m.group(1));

    String confirmPath;
    try {
      confirmPath = _confirmationService.confirm(key);
      if (confirmPath != null) {
        response.sendRedirect(confirmPath);
      } else {
        // handled, but not a valid confirmation
        response.sendError(404);
      }
      return true;
    } catch (ConfirmationException e) {
      // not handled by confirmation service, follow filter chain
      return false;
    }
  }

  private String decode(String string) {
    try {
      return URLDecoder.decode(string, CharsetUtils.UTF_8.name());
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("UTF-8 not supported?", e);
    }
  }

  private String encode(String string) {
    try {
      return URLEncoder.encode(string, CharsetUtils.UTF_8.name());
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("UTF-8 not supported?", e);
    }
  }

  private IPullChannel getChannel(String channelId) {
    return _channels.get(channelId);
  }

  @Override
  public String toPullPath(String channelId, String userId, IParams params) {
    IPullChannel channel = getChannel(channelId);
    if (channel == null) {
      return null;
    }

    IChannelPreferences cPrefs = channel.newDefaultPreferences();

    IParams fullParams = new Params().setAll(cPrefs.getParams()).setAll(params);

    StringBuilder buf = new StringBuilder(_baseUrl);
    buf.append(_mountPath).append(_pullPrefix).append(channelId).append("/").append(userId);
    buf.append("?");
    for (final ParamValue pv : fullParams) {
      final String encodedName = encode(pv.getName());
      final String value = pv.getStringValue();
      final String encodedValue = value != null ? encode(value) : "";

      buf.append(encodedName);
      buf.append("=");
      buf.append(encodedValue);
      buf.append("&");
    }
    buf.setLength(buf.length() - 1);
    return buf.toString();
  }

  @Override
  public String toConfirmPath(Confirmation confirmation) {
    return _baseUrl + _mountPath + _confirmPrefix + confirmation.getKey();
  }

  public String getBaseUrl() {
    return _baseUrl;
  }

  public void setBaseUrl(String baseUrl) {
    _baseUrl = baseUrl;
  }

  public String getBaseUrlProperty() {
    return _baseUrlProperty;
  }

  public void setBaseUrlProperty(String baseUrlProperty) {
    _baseUrlProperty = baseUrlProperty;
  }

  public String getMountPath() {
    return _mountPath;
  }

  public void setMountPath(String mountPath) {
    _mountPath = mountPath;
  }

  public String getPullPrefix() {
    return _pullPrefix;
  }

  public void setPullPrefix(String pullPrefix) {
    _pullPrefix = pullPrefix;
  }

  public String getConfirmPrefix() {
    return _confirmPrefix;
  }

  public void setConfirmPrefix(String confirmPrefix) {
    _confirmPrefix = confirmPrefix;
  }

  public void setChannels(Set<IPullChannel> channels) {
    _channels.clear();
    for (IPullChannel channel : channels) {
      _channels.put(channel.getId(), channel);
    }
  }

  public void setConfirmationService(IConfirmationService confirmationService) {
    _confirmationService = confirmationService;
  }

}
TOP

Related Classes of at.molindo.notify.servlet.NotifyFilterBean

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.