日历
网志分类
· 所有网志 (57)
· 技术 (21)
· 牢骚 (17)
· 未分类 (19)
最新的评论
站内搜索
友情链接
· 我的歪酷 非非共享界
· google
· developerworks
· MDA,UML,XML,Eclipse及Java相关的Blog
· 葛大姐
· 施大姐
· 陆小妹
· msg
· howImiss
· 第二书店
· http://www.csdn.net/
· http://www.itpub.net/
· 爬爬大陆漫画专区
· 唧唧歪歪在线漫画

订阅 RSS

0027557

歪酷博客

我是风,xiu~~~~


xiuxiu @ 2007-12-12 23:47

锻炼过程:
登山机,5分钟,30千卡
溜冰机,5分钟,40千卡
自行车,5分钟,10千卡

其后在poison唆使下
尝试难度5下速度180...遂挂

症状:
极度眩晕
面无血色
无法站立

战果:
poison慰问品维体一瓶

前序
感冒两周
当天拉肚子
中饭晚饭都没吃....

哎哎,我的第一次...


 
xiuxiu @ 2007-12-11 22:44

感冒了两个礼拜, 体力透支,四肢酸软, 懒洋洋的躺在星巴克的沙发上, 看着mm兴趣盎然的看杂志, 此时最合适的约会方式了吧, 星巴克真是一个有趣的小世界 左边银幕矩阵的sales jj在给一个男人演示ppt 前方一家人因为女婿嗜赌卖房在无奈的咨询着律师 右边一对白领丽人邀约taobao卖家咨询PSP的事宜 背后一个光头的马克杯男认真的复习着免疫学 我,看着the ruby way 一边感叹其强大 一边感叹自己无聊 还是没啥练手的机会 有点失去了动力


 
xiuxiu @ 2007-11-29 00:26

其后我阅读了acegi的源代码, 得到以下结论:
1)Acegi通过HttpSessionContextIntergrationFilter在Session中保留认证信息,让不同的请求共享这些信息.
2)Acegi通过SecurityHolder在ThreadLocale(可选择Strategy)中保留认证信息,让一次请求的不同Filter共享这些信息.
最终,把目标锁定在了HttpSessionContextIntergrationFilter(我也真笨,人家这么明显的一个名字-,-).
水平不够,也就照抄了一下人家的源码,把session.setAtribute(),session.getAttribute()替换了.

/**
 *
 */
package com.xiuxiu.acegimemcached.cache;

import java.io.IOException;
import java.lang.reflect.Method;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import net.spy.memcached.MemcachedClient;

import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.context.SecurityContextImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

/**
 * @author Xiu
 *
 */
public class MemcachedContextIntegrationFilter implements InitializingBean,
        Filter {

    //~ Static fields/initializers =====================================================================================

    protected static final Log logger = LogFactory.getLog(HttpSessionContextIntegrationFilter.class);
    private static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied";
    public static final String ACEGI_SECURITY_CONTEXT_KEY = "ACEGI_SECURITY_CONTEXT";

    //~ Instance fields ================================================================================================

    private Class context = SecurityContextImpl.class;
    private Object contextObject;
    private static int EXP = 3000;   
    private MemcachedClient memcachedClient;

    /**
     * Indicates if this filter can create a <code>HttpSession</code> if needed (sessions are always created
     * sparingly, but setting this value to <code>false</code> will prohibit sessions from ever being created).
     * Defaults to <code>true</code>. Do not set to <code>false</code> if you are have set {@link
     * #forceEagerSessionCreation} to <code>true</code>, as the properties would be in conflict.
     */
    private boolean allowSessionCreation = true;

    /**
     * Indicates if this filter is required to create a <code>HttpSession</code> for every request before
     * proceeding through the filter chain, even if the <code>HttpSession</code> would not ordinarily have been
     * created. By default this is <code>false</code>, which is entirely appropriate for most circumstances as you do
     * not want a <code>HttpSession</code> created unless the filter actually needs one. It is envisaged the main
     * situation in which this property would be set to <code>true</code> is if using other filters that depend on a
     * <code>HttpSession</code> already existing, such as those which need to obtain a session ID. This is only
     * required in specialised cases, so leave it set to <code>false</code> unless you have an actual requirement and
     * are conscious of the session creation overhead.
     */
    private boolean forceEagerSessionCreation = false;
   
    /**
     * Indicates whether the <code>SecurityContext</code> will be cloned from the <code>HttpSession</code>. The
     * default is to simply reference (ie the default is <code>false</code>). The default may cause issues if
     * concurrent threads need to have a different security identity from other threads being concurrently processed
     * that share the same <code>HttpSession</code>. In most normal environments this does not represent an issue,
     * as changes to the security identity in one thread is allowed to affect the security identitiy in other
     * threads associated with the same <code>HttpSession</code>. For unusual cases where this is not permitted,
     * change this value to <code>true</code> and ensure the {@link #context} is set to a <code>SecurityContext</code>
     * that implements {@link Cloneable} and overrides the <code>clone()</code> method.
     */
    private boolean cloneFromHttpSession = false;

    public boolean isCloneFromHttpSession() {
        return cloneFromHttpSession;
    }

    public void setCloneFromHttpSession(boolean cloneFromHttpSession) {
        this.cloneFromHttpSession = cloneFromHttpSession;
    }

    public MemcachedContextIntegrationFilter() throws ServletException {
        this.contextObject = generateNewContext();
    }

    //~ Methods ========================================================================================================

    public void afterPropertiesSet() throws Exception {
        if ((this.context == null) || (!SecurityContext.class.isAssignableFrom(this.context))) {
            throw new IllegalArgumentException(
                "context must be defined and implement SecurityContext (typically use org.acegisecurity.context.SecurityContextImpl; existing class is "
                + this.context + ")");
        }

        if ((forceEagerSessionCreation == true) && (allowSessionCreation == false)) {
            throw new IllegalArgumentException(
                "If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
        }
    }

    /**
     * Does nothing. We use IoC container lifecycle services instead.
     */
    public void destroy() {}

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) {
            // ensure that filter is only applied once per request
            chain.doFilter(request, response);
        } else {
            if (request != null) {
                request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
            }

            HttpSession httpSession = null;
            boolean httpSessionExistedAtStartOfRequest = false;

            try {
                httpSession = ((HttpServletRequest) request).getSession(forceEagerSessionCreation);
            } catch (IllegalStateException ignored) {}

            if (httpSession != null) {
                httpSessionExistedAtStartOfRequest = true;

                Object contextFromSessionObject = this.memcachedClient.get(String.valueOf(httpSession.getId()));
               
                // Clone if required (see SEC-356)
                if (cloneFromHttpSession) {
                    Assert.isInstanceOf(Cloneable.class, contextFromSessionObject, "Context must implement Clonable and provide a Object.clone() method");
                    try {
                        Method m = contextFromSessionObject.getClass().getMethod("clone", new Class[] {});
                        if (!m.isAccessible()) {
                            m.setAccessible(true);
                        }
                        contextFromSessionObject = m.invoke(contextFromSessionObject, new Object[] {});
                    } catch (Exception ex) {
                        ReflectionUtils.handleReflectionException(ex);
                    }
                }
               
                if (contextFromSessionObject != null) {
                    if (contextFromSessionObject instanceof SecurityContext) {
                        if (logger.isDebugEnabled()) {
                            logger.debug(
                                "Obtained from ACEGI_SECURITY_CONTEXT a valid SecurityContext and set to SecurityContextHolder: '"
                                + contextFromSessionObject + "'");
                        }

                        SecurityContextHolder.setContext((SecurityContext) contextFromSessionObject);
                    } else {
                        if (logger.isWarnEnabled()) {
                            logger.warn("ACEGI_SECURITY_CONTEXT did not contain a SecurityContext but contained: '"
                                + contextFromSessionObject
                                + "'; are you improperly modifying the HttpSession directly (you should always use SecurityContextHolder) or using the HttpSession attribute reserved for this class? - new SecurityContext instance associated with SecurityContextHolder");
                        }

                        SecurityContextHolder.setContext(generateNewContext());
                    }
                } else {
                    if (logger.isDebugEnabled()) {
                        logger.debug(
                            "HttpSession returned null object for ACEGI_SECURITY_CONTEXT - new SecurityContext instance associated with SecurityContextHolder");
                    }

                    SecurityContextHolder.setContext(generateNewContext());
                }
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug(
                        "No HttpSession currently exists - new SecurityContext instance associated with SecurityContextHolder");
                }

                SecurityContextHolder.setContext(generateNewContext());
            }

            // Make the HttpSession null, as we want to ensure we don't keep
            // a reference to the HttpSession laying around in case the
            // chain.doFilter() invalidates it.
            httpSession = null;

            // Proceed with chain
            int contextWhenChainProceeded = SecurityContextHolder.getContext().hashCode();

            try {
                chain.doFilter(request, response);
            } catch (IOException ioe) {
                throw ioe;
            } catch (ServletException se) {
                throw se;
            } finally {
                // do clean up, even if there was an exception
                // Store context back to HttpSession
                try {
                    httpSession = ((HttpServletRequest) request).getSession(false);
                } catch (IllegalStateException ignored) {}

                if ((httpSession == null) && httpSessionExistedAtStartOfRequest) {
                    if (logger.isDebugEnabled()) {
                        logger.debug(
                            "HttpSession is now null, but was not null at start of request; session was invalidated, so do not create a new session");
                    }
                }

                // Generate a HttpSession only if we need to
                if ((httpSession == null) && !httpSessionExistedAtStartOfRequest) {
                    if (!allowSessionCreation) {
                        if (logger.isDebugEnabled()) {
                            logger.debug(
                                "The HttpSession is currently null, and the HttpSessionContextIntegrationFilter is prohibited from creating a HttpSession (because the allowSessionCreation property is false) - SecurityContext thus not stored for next request");
                        }
                    } else if (!contextObject.equals(SecurityContextHolder.getContext())) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("HttpSession being created as SecurityContextHolder contents are non-default");
                        }

                        try {
                            httpSession = ((HttpServletRequest) request).getSession(true);
                        } catch (IllegalStateException ignored) {}
                    } else {
                        if (logger.isDebugEnabled()) {
                            logger.debug(
                                "HttpSession is null, but SecurityContextHolder has not changed from default: ' "
                                + SecurityContextHolder.getContext()
                                + "'; not creating HttpSession or storing SecurityContextHolder contents");
                        }
                    }
                }

                // If HttpSession exists, store current SecurityContextHolder
                // contents
                // but only if SecurityContext has actually changed (see JIRA
                // SEC-37)
                if ((httpSession != null)
                    && (SecurityContextHolder.getContext().hashCode() != contextWhenChainProceeded)) {
                    this.memcachedClient.set(httpSession.getId(), EXP , SecurityContextHolder.getContext());

                    if (logger.isDebugEnabled()) {
                        logger.debug("SecurityContext stored to HttpSession: '" + SecurityContextHolder.getContext()
                            + "'");
                    }
                }

                // Remove SecurityContextHolder contents
                SecurityContextHolder.clearContext();

                if (logger.isDebugEnabled()) {
                    logger.debug("SecurityContextHolder set to new context, as request processing completed");
                }
            }
        }
    }

    public SecurityContext generateNewContext() throws ServletException {
        try {
            return (SecurityContext) this.context.newInstance();
        } catch (InstantiationException ie) {
            throw new ServletException(ie);
        } catch (IllegalAccessException iae) {
            throw new ServletException(iae);
        }
    }

    public Class getContext() {
        return context;
    }

    /**
     * Does nothing. We use IoC container lifecycle services instead.
     *
     * @param filterConfig ignored
     *
     * @throws ServletException ignored
     */
    public void init(FilterConfig filterConfig) throws ServletException {}

    public boolean isAllowSessionCreation() {
        return allowSessionCreation;
    }

    public boolean isForceEagerSessionCreation() {
        return forceEagerSessionCreation;
    }

    public void setAllowSessionCreation(boolean allowSessionCreation) {
        this.allowSessionCreation = allowSessionCreation;
    }

    public void setContext(Class secureContext) {
        this.context = secureContext;
    }

    public void setForceEagerSessionCreation(boolean forceEagerSessionCreation) {
        this.forceEagerSessionCreation = forceEagerSessionCreation;
    }

    /**
     * @return the memcachedClient
     */
    public MemcachedClient getMemcachedClient() {
        return memcachedClient;
    }

    /**
     * @param memcachedClient the memcachedClient to set
     */
    public void setMemcachedClient(MemcachedClient memcachedClient) {
        this.memcachedClient = memcachedClient;
    }
}

    <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
        <property name="filterInvocationDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /**=memcachedContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
            </value>
        </property>
    </bean>

    <bean id="memcachedContextIntegrationFilter" class="com.xiuxiu.acegimemcached.cache.MemcachedContextIntegrationFilter">
                <property name="memcachedClient" ref="memcachedClient"/>
    </bean>

测试成功,ohyeah....

后记:对于(一)中提到的第二篇文章一直有一些误解.他是对用户-->角色,角色-->权限的信息进行扩展并且缓存,而不是对当前用户的信息进行缓存.一开始走了很多弯路.
5 performance test + concurrency test ( to be continued )
6 java client source code and memcached source code Reading ( to be continued )



 
xiuxiu @ 2007-11-28 14:47

好奇心重的特点最近有点被放大夸大了....
看了很多文章,看了很多书,各种技术的兴趣好奇心都被慢慢培养了起来

RoR:
按照<基于RoR的敏捷开发>的例子写了一个Sample,直接被震撼了.
不管是其中包含的敏捷开发方法,还是与REST,Ajax的整合,让人信服的DRY,
都让我非常希望好好学习一下.

现在继续在读这本好书,又想多看一些Ruby的基础书籍.
另外又想看看RoR + REST的文章,可是最近又没有什么练手的机会..........混乱了

RCP:
安装<Eclipse Rich Client Platform Designing  Coding and Packaging Java Application>
做了一个IM的example,又被震撼了.
正好最近项目又一个机会,就作了个超级简单的tools,还是非常满意的.

现在一方面这本书看到一半,需要进一步了解RCP其中的架构,OSGi的精髓
另外一方面想把rcp 和 spring整合,进一步作成rcp + spring remote的富客户端.
哎哎,混乱阿...

web2.0
大访问量,大并发量,这都是我对Web开发的最高憧憬.
最近读了程序员的增刊Web.20,被这些网站的成就和架构深深地吸引了.
mysql的集群,水平,垂直分割,
lighttpd, apache的集群, 负载均衡,
flat file, memcached,,,,等等等等,多么神圣的领域
最近只有空做了memcached的尝试,一下子解决了之前困扰我很久的问题(acegi in memory),
可惜其他东西就没有那么容易尝试了,,,混乱了....

RIA
RIA的丰富客户体验使得它必将成为一个巨大的市场.openLaszlo, Flex , SliverLight,
众多的解决方案让人目不暇接. 可是语言和时间的掌握让我仍然没有机会去尝试.
本来想看看OpenLaszlo,可是落后的开发工具让人望而却步.
下一步希望能了解一下Flex,掌握基础的开发能力.



 
xiuxiu @ 2007-11-27 10:07

        给土豆做的网站要做集群. 众所周知,集群服务器之间的Session共享是一个致命的问题.而Acegi使用的基于Session内存的实现机制使得问题难以调和.
       正好最近在看程序员增刊--Web2.0.其中强烈推荐了分布式的缓存服务器memcached.感觉能解决目前的问题.所以就打算研究一下.
1 memcached 的安装
memcached的下载
www.danga.com/memcached/
memcached的安装
 ttitfly.javaeye.com/blog/110112

这篇文章比较细致.也遇到了其中说得找不到.so文件的错误,建立一个link就搞定了.

2 Java memcached client
memcached Java Client API
www.danga.com/memcached/apis.bml
我使用了Dustin Sallings写的Improved API
bleu.west.spy.net/~dustin/projects/memcached/

下载memcached client, spy 两个jar包.
然后安装简要说明就可以实现了.


3 Ruby memcached client
1)下载memcached client
gem install memcache-client
2)sample code
我使用的是Aptana IDE,对RoR集成得非常好.参照memcached client的Rdoc,创建了一个HelloWorld.rb.

require 'memcache'

  cache = MemCache::new '10.0.0.15:11211',
                       :debug => true,
                       :c_threshold => 100_000,
                       :compression => false,
                       :namespace => 'foo'

  # Cache simple values with simple String or Symbol keys
  cache["my_key"] = "Some value"
  cache[:other_key] = "Another value"

  # ...or more-complex values
  cache["object_key"] = { 'complex' => [ "object", 2, 4 ] }

  # ...or more-complex keys
  cache[ Time::now.to_a[1..7] ] ||= 0

  val = cache["my_key"]               # => "Some value"
  val = cache["object_key"]           # => {"complex" => ["object",2,4]}
  print val['complex'][2]             # => 4

4 acegi + memcached ( to be continued )
参考文章
www.java-asp.net/java/200512/t_48588.html
www.springside.org.cn/docs/reference/Acegi4.htm
如同第一篇文章中作者所说的,acegi基于spring以及interface的设计确实非常的灵活方便.
只需要实现org.acegisecurity.providers.dao.UserCache这个接口,就可以轻松的集成acegi +memcached.(想想而已,晚上回家实现一把)

昨晚想的还是太简单了,按照第一篇文章说的,确实能够实现分布式缓存.但是只能实现登陆信息数据库的分布式缓存.
也就是说如果我下次登陆被负载均衡分配到了另外一台陌生的服务器,系统同样可以从缓存而不是数据库读取权限信息.这与我的初衷还是有所不同的,使用了acegi自带的acegi-security-sample-tutorial.war,实现如下.
/**
 *
 */
package com.xiuxiu.acegimemcached.cache;

import net.spy.memcached.MemcachedClient;

import org.acegisecurity.providers.dao.UserCache;
import org.acegisecurity.userdetails.UserDetails;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.util.Assert;

/**
 * @author Xiu
 *
 */
public class MemcachedUserCache implements UserCache, InitializingBean {

    private static final Log logger = LogFactory.getLog(MemcachedUserCache.class);
    private static int EXP = 3000;
   
    private MemcachedClient memcachedClient;
   
    public MemcachedUserCache(){
    }
    /**
     * @return the cache
     */
    public MemcachedClient getMemcachedClient() {
        return memcachedClient;
    }
    /**
     * @param cache the cache to set
     */
    public void setMemcachedClient(MemcachedClient memcachedClient) {
        this.memcachedClient = memcachedClient;
    }
    /* (non-Javadoc)
     * @see org.acegisecurity.providers.dao.UserCache#getUserFromCache(java.lang.String)
     */
    public UserDetails getUserFromCache(String username) {
        Object element = null;

        try {
            element = memcachedClient.get(username);
        } catch (RuntimeException cacheException) {
            throw new DataRetrievalFailureException("Cache failure: " + cacheException.getMessage());
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Cache hit: " + (element != null) + "; username: " + username);
        }

        if (element == null) {
            return null;
        } else {
            return (UserDetails) element;
        }
    }

    /* (non-Javadoc)
     * @see org.acegisecurity.providers.dao.UserCache#putUserInCache(org.acegisecurity.userdetails.UserDetails)
     */
    public void putUserInCache(UserDetails user) {

        if (logger.isDebugEnabled()) {
            logger.debug("Cache put: " + user.getUsername());
        }

        memcachedClient.set(user.getUsername(), EXP, user);

    }

    /* (non-Javadoc)
     * @see org.acegisecurity.providers.dao.UserCache#removeUserFromCache(java.lang.String)
     */
    public void removeUserFromCache(String username) {
        memcachedClient.delete(username);

    }

    /* (non-Javadoc)
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    public void afterPropertiesSet() throws Exception {
         Assert.notNull(memcachedClient, "cache mandatory");
    }
}

     <bean id="memcachedClient" class="net.spy.memcached.MemcachedClient">
        <constructor-arg>           
             <bean class="java.net.InetSocketAddress">
                <constructor-arg  type="java.lang.String"  value="192.168.1.3"/>
                <constructor-arg  type="int" value="11211"/>
             </bean>
        </constructor-arg>
     </bean>
    <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
        <property name="userDetailsService" ref="userDetailsService"/>
        <property name="userCache">
            <bean class="com.xiuxiu.acegimemcached.cache.MemcachedUserCache">
                <property name="memcachedClient" ref="memcachedClient"/>
            </bean>
        </property>
    </bean>