paulwong

          #

          JAX-RS客戶端的測試工具,帶UI

          https://code.google.com/p/rest-client/downloads/detail?name=restclient-ui-3.2.1-jar-with-dependencies.jar&can=2&q=

          posted @ 2013-11-19 16:42 paulwong 閱讀(433) | 評論 (0)編輯 收藏

          SPRING DATA查詢方法

          SPRING DATA的REPOSITORY由于只是一個接口,沒有實現方法的,因此查詢就要結合注釋或方法進行:
          通過解析方法名創建查詢
          通過前面的例子,讀者基本上對解析方法名創建查詢的方式有了一個大致的了解,這也是 Spring Data JPA 吸引開發者的一個很重要的因素。該功能其實并非 Spring Data JPA 首創,而是源自一個開源的 JPA 框架 Hades,該框架的作者 Oliver Gierke 本身又是 Spring Data JPA 項目的 Leader,所以把 Hades 的優勢引入到 Spring Data JPA 也就是順理成章的了。


          框架在進行方法名解析時,會先把方法名多余的前綴截取掉,比如 find、findBy、read、readBy、get、getBy,然后對剩下部分進行解析。并且如果方法的最后一個參數是 Sort 或者 Pageable 類型,也會提取相關的信息,以便按規則進行排序或者分頁查詢。


          在創建查詢時,我們通過在方法名中使用屬性名稱來表達,比如 findByUserAddressZip ()??蚣茉诮馕鲈摲椒〞r,首先剔除 findBy,然后對剩下的屬性進行解析,詳細規則如下(此處假設該方法針對的域對象為 AccountInfo 類型):


          先判斷 userAddressZip (根據 POJO 規范,首字母變為小寫,下同)是否為 AccountInfo 的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,繼續第二步;


          從右往左截取第一個大寫字母開頭的字符串(此處為 Zip),然后檢查剩下的字符串是否為 AccountInfo 的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,則重復第二步,繼續從右往左截取;最后假設 user 為 AccountInfo 的一個屬性;


          接著處理剩下部分( AddressZip ),先判斷 user 所對應的類型是否有 addressZip 屬性,如果有,則表示該方法最終是根據 "AccountInfo.user.addressZip" 的取值進行查詢;否則繼續按照步驟 2 的規則從右往左截取,最終表示根據 "AccountInfo.user.address.zip" 的值進行查詢。


          可能會存在一種特殊情況,比如 AccountInfo 包含一個 user 的屬性,也有一個 userAddress 屬性,此時會存在混淆。讀者可以明確在屬性之間加上 "_" 以顯式表達意圖,比如 "findByUser_AddressZip()" 或者 "findByUserAddress_Zip()"。


          在查詢時,通常需要同時根據多個屬性進行查詢,且查詢的條件也格式各樣(大于某個值、在某個范圍等等),Spring Data JPA 為此提供了一些表達條件查詢的關鍵字,大致如下:


          And --- 等價于 SQL 中的 and 關鍵字,比如 findByUsernameAndPassword(String user, Striang pwd);

          Or --- 等價于 SQL 中的 or 關鍵字,比如 findByUsernameOrAddress(String user, String addr);

          Between --- 等價于 SQL 中的 between 關鍵字,比如 findBySalaryBetween(int max, int min);

          LessThan --- 等價于 SQL 中的 "<",比如 findBySalaryLessThan(int max);

          GreaterThan --- 等價于 SQL 中的">",比如 findBySalaryGreaterThan(int min);

          IsNull --- 等價于 SQL 中的 "is null",比如 findByUsernameIsNull();

          IsNotNull --- 等價于 SQL 中的 "is not null",比如 findByUsernameIsNotNull();

          NotNull --- 與 IsNotNull 等價;

          Like --- 等價于 SQL 中的 "like",比如 findByUsernameLike(String user);

          NotLike --- 等價于 SQL 中的 "not like",比如 findByUsernameNotLike(String user);

          OrderBy --- 等價于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user);

          Not --- 等價于 SQL 中的 "! =",比如 findByUsernameNot(String user);

          In --- 等價于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的參數可以是 Collection 類型,也可以是數組或者不定長參數;

          NotIn --- 等價于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的參數可以是 Collection 類型,也可以是數組或者不定長參數;


          同時我們也可以自定義自己的方式查詢通過@Query注解 這里可以參考http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-jpa/ 這篇文章,注意的是JPA 所以@query里面的內容是HQL 如果是mongodb那么語法就是mongodb的查詢語法 neo4j就是neo4j的查詢語法

          posted @ 2013-11-17 11:38 paulwong 閱讀(437) | 評論 (0)編輯 收藏

          SPRING各種例子

          spring-mvc-rest
          https://github.com/skprasadu/spring-mvc-rest


          spring-mvc-examples
          https://github.com/skprasadu/spring-mvc-examples


          spring-security-examples
          https://github.com/skprasadu/spring-security-examples


          pro-spring-mvc-code
          https://github.com/mdeinum/pro-spring-mvc-code










          posted @ 2013-11-11 14:44 paulwong 閱讀(377) | 評論 (0)編輯 收藏

          SPRINGMVC增加LOGBACK

          Maven的pom.xml增加兩個JAR
          <dependency>
                  <groupId>org.slf4j</groupId>
                  <artifactId>jcl-over-slf4j</artifactId>
                  <version>1.7.2</version>      
          </dependency>
                
          <dependency>
                  <groupId>ch.qos.logback</groupId>
                  <artifactId>logback-classic</artifactId>
                  <version>1.0.9</version>      
          </dependency>


          web.xml
          <!-- spring logback -->  
          <context-param>  
              <param-name>logbackConfigLocation</param-name>  
              <param-value>classpath:logback.xml</param-value>  
          </context-param>    
          <listener>  
              <listener-class>mypackage.LogbackConfigListener</listener-class>  
          </listener>  


          logback.xml
          <?xml version="1.0" encoding="UTF-8" ?>
          <configuration>

              <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
                  <encoder>
                      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
                      </pattern>
                  </encoder>
              </appender>

              <appender name="FILE" class="ch.qos.logback.core.FileAppender">
                  <file>bookstore.log</file>
                  <encoder>
                      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
                      </pattern>
                  </encoder>
              </appender>

              <logger name="org.springframework" level="INFO" />
              <logger name="org.springframework.web" level="INFO" />


              <root level="INFO">
                  <appender-ref ref="STDOUT" />
                  <!-- <appender-ref ref="FILE" /> -->
              </root>

          </configuration>



          LogbackConfigurer.java
          import java.io.File;
          import java.io.FileNotFoundException;
          import java.net.URL;

          import org.slf4j.LoggerFactory;
          import org.springframework.util.ResourceUtils;
          import org.springframework.util.SystemPropertyUtils;

          import ch.qos.logback.classic.LoggerContext;
          import ch.qos.logback.classic.joran.JoranConfigurator;
          import ch.qos.logback.core.joran.spi.JoranException;


          public abstract class LogbackConfigurer {

              /** Pseudo URL prefix for loading from the class path: "classpath:" */
              public static final String       CLASSPATH_URL_PREFIX = "classpath:";

              /** Extension that indicates a logback XML config file: ".xml" */
              public static final String       XML_FILE_EXTENSION   = ".xml";

              private static LoggerContext     lc                   = (LoggerContext) LoggerFactory.getILoggerFactory();
              private static JoranConfigurator configurator         = new JoranConfigurator();

              /**
               * Initialize logback from the given file location, with no config file refreshing. Assumes an XML file in case of a ".xml" file extension, and a properties file otherwise.
               * 
               * 
          @param location
               *            the location of the config file: either a "classpath:" location (e.g. "classpath:mylogback.properties"), an absolute file URL (e.g. "file:C:/logback.properties), or a plain absolute path in the file system (e.g. "C:/logback.properties")
               * 
          @throws FileNotFoundException
               *             if the location specifies an invalid file path
               
          */
              public static void initLogging(String location) throws FileNotFoundException {
                  String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
                  URL url = ResourceUtils.getURL(resolvedLocation);
                  if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) {
          //            DOMConfigurator.configure(url);
                      configurator.setContext(lc);
                      lc.reset();
                      try {
                          configurator.doConfigure(url);
                      } catch (JoranException ex) {
                          throw new FileNotFoundException(url.getPath());
                      }
                      lc.start();
                  }
          //        else {
          //            PropertyConfigurator.configure(url);
          //        }
              }

              /**
               * Shut down logback, properly releasing all file locks.
               * <p>
               * This isn't strictly necessary, but recommended for shutting down logback in a scenario where the host VM stays alive (for example, when shutting down an application in a J2EE environment).
               
          */
              public static void shutdownLogging() {
                  lc.stop();
              }

              /**
               * Set the specified system property to the current working directory.
               * <p>
               * This can be used e.g. for test environments, for applications that leverage logbackWebConfigurer's "webAppRootKey" support in a web environment.
               * 
               * 
          @param key
               *            system property key to use, as expected in logback configuration (for example: "demo.root", used as "${demo.root}/WEB-INF/demo.log")
               * 
          @see org.springframework.web.util.logbackWebConfigurer
               
          */
              public static void setWorkingDirSystemProperty(String key) {
                  System.setProperty(key, new File("").getAbsolutePath());
              }

          }


          LogbackWebConfigurer.java
          import java.io.FileNotFoundException;

          import javax.servlet.ServletContext;

          import org.springframework.util.ResourceUtils;
          import org.springframework.util.SystemPropertyUtils;
          import org.springframework.web.util.WebUtils;

          public abstract class LogbackWebConfigurer {

              /** Parameter specifying the location of the logback config file */
              public static final String CONFIG_LOCATION_PARAM     = "logbackConfigLocation";

              /** Parameter specifying the refresh interval for checking the logback config file */
              public static final String REFRESH_INTERVAL_PARAM    = "logbackRefreshInterval";

              /** Parameter specifying whether to expose the web app root system property */
              public static final String EXPOSE_WEB_APP_ROOT_PARAM = "logbackExposeWebAppRoot";

              /**
               * Initialize logback, including setting the web app root system property.
               * 
               * 
          @param servletContext
               *            the current ServletContext
               * 
          @see WebUtils#setWebAppRootSystemProperty
               
          */
              public static void initLogging(ServletContext servletContext) {
                  // Expose the web app root system property.
                  if (exposeWebAppRoot(servletContext)) {
                      WebUtils.setWebAppRootSystemProperty(servletContext);
                  }

                  // Only perform custom logback initialization in case of a config file.
                  String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
                  if (location != null) {
                      // Perform actual logback initialization; else rely on logback's default initialization.
                      try {
                          // Return a URL (e.g. "classpath:" or "file:") as-is;
                          
          // consider a plain file path as relative to the web application root directory.
                          if (!ResourceUtils.isUrl(location)) {
                              // Resolve system property placeholders before resolving real path.
                              location = SystemPropertyUtils.resolvePlaceholders(location);
                              location = WebUtils.getRealPath(servletContext, location);
                          }

                          // Write log message to server log.
                          servletContext.log("Initializing logback from [" + location + "]");

                          // Initialize without refresh check, i.e. without logback's watchdog thread.
                          LogbackConfigurer.initLogging(location);

                      } catch (FileNotFoundException ex) {
                          throw new IllegalArgumentException("Invalid 'logbackConfigLocation' parameter: " + ex.getMessage());
                      }
                  }
              }

              /**
               * Shut down logback, properly releasing all file locks and resetting the web app root system property.
               * 
               * 
          @param servletContext
               *            the current ServletContext
               * 
          @see WebUtils#removeWebAppRootSystemProperty
               
          */
              public static void shutdownLogging(ServletContext servletContext) {
                  servletContext.log("Shutting down logback");
                  try {
                      LogbackConfigurer.shutdownLogging();
                  } finally {
                      // Remove the web app root system property.
                      if (exposeWebAppRoot(servletContext)) {
                          WebUtils.removeWebAppRootSystemProperty(servletContext);
                      }
                  }
              }

              /**
               * Return whether to expose the web app root system property, checking the corresponding ServletContext init parameter.
               * 
               * 
          @see #EXPOSE_WEB_APP_ROOT_PARAM
               
          */
              private static boolean exposeWebAppRoot(ServletContext servletContext) {
                  String exposeWebAppRootParam = servletContext.getInitParameter(EXPOSE_WEB_APP_ROOT_PARAM);
                  return (exposeWebAppRootParam == null || Boolean.valueOf(exposeWebAppRootParam));
              }

          }


          LogbackConfigListener.java
          import javax.servlet.ServletContextEvent;
          import javax.servlet.ServletContextListener;

          public class LogbackConfigListener implements ServletContextListener {

              public void contextInitialized(ServletContextEvent event) {
                  LogbackWebConfigurer.initLogging(event.getServletContext());
              }

              public void contextDestroyed(ServletContextEvent event) {
                  LogbackWebConfigurer.shutdownLogging(event.getServletContext());
              }
          }



          posted @ 2013-11-11 13:44 paulwong 閱讀(4764) | 評論 (0)編輯 收藏

          大型網站技術架構讀書筆記

          大型網站經歷的技術架構演變:
          1. 應用服務器、數據庫服務器和文件服務器都安裝在同一臺主機
          2. 應用服務器、數據庫服務器和文件服務器分別安裝在不同主機
          3. 增加了分布式的緩存服務器
          4. 應用服務器增加了好幾臺,變成集群
          5. 增加了CDN和反射代理服務器
          6. 數據庫服務器變成主從形式的服務器
          7. 數據庫服務器變成分布式的服務器,文件服務器也變成分布式服務器
          8. NOSQL分布式數據庫和搜索引擎的引入
          9. 應用服務器雖然是多臺,但都是部署了同一應用,這時將應用拆分,每臺服務器部署不同的拆分應用
          10. 雖然應用已經拆分,但每個應用都是從頁面管到數據庫,這時繼續拆分,將存取數據庫的部份獨立,頁面部份
            也獨立
          架構模式
          1. 分層,代碼放在不同的類中
          2. 分割,應用放在不同的JVM中
          3. 分布式,部署在不同的物理機
          4. 集群,同一個應用部署到不同的主機,可以負載均衡
          5. 緩存,CND加速、反向代理、本地緩存、分布式緩存
          6. 異步,消除高并發
          7. 冗余,多處備份
          8. 安全性

          posted @ 2013-11-09 11:34 paulwong 閱讀(654) | 評論 (0)編輯 收藏

          Java EE 8愿望清單:缺少這些,Java EE將不會完美

          摘要:Java EE 7已于6月中旬正式發布,盡管新平臺包含了諸多新的特性,但是開發者對此似乎并不滿足,他們期待未來的版本Java EE 8中能夠包含更完善的特性,比如更大的CDI應用范圍、標準的緩存API、現代化的安全框架等。

          Java EE 7已于6月中旬正式發布,新版本提供了一個強大、完整、全面的堆棧來幫助開發者構建企業和Web應用程序——為構建HTML5動態可伸縮應用程序提供了支持,并新增大量規范和特性來提高開發人員的生產力以及滿足企業最苛刻的需求。

          下面的這個圖表包含了Java EE 7中的各種組件。橙色部分為Java EE中新添加的組件。

          盡管新的平臺包含了諸多新的特性,但是開發者對此似乎并不滿足,盡管他們中的大部分還沒有遷移到Java EE 7(或許是由于Java EE 7的特性還不完善),但是這并不影響他們對于Java EE 8特性的設想。

          比如,在Java EE 6發布(2009年12月10日發布)后,開發者Antonio Goncalves認為該版本并沒有解決一些問題,因此寫了一個希望在Java EE 7中包含的特性清單。有趣的是,他寫的4個特性中,其中有2個(flows和batch)已經包含在Java EE 7中了,而第3個特性(caching)原本也計劃包含其中,但由于開發進度關系,在Java EE 7最終發布前被舍棄。

          此舉促使開發者Arjan Tijms也寫了一個他希望在Java EE 8中出現的特性清單,如下。

          1. 無處不在的CDI(Contexts and Dependency Injection for Java EE,上下文與依賴注入)
          2. 更深入的Pruning(修剪)和Deprecating(棄用)
          3. 一個標準的緩存API
          4. administrative objects(管理對象)的應用內替代品
          5. 綜合的現代化的安全框架
          6. 平臺范圍內的配置

          下面就來詳細闡述這些特性的必要性。

          1.  無處不在的CDI

          實際上這意味著2種不同的東西:使CDI可以用在目前不能用的其他地方、基于CDI來實現和改造其他規范中的相關技術。

          a. 使CDI可以用在其他地方

          與Java EE 6相比,Java EE 7中的CDI的適用范圍已經擴大了很多,比如CDI注入現在可以工作在大多數JSF組件(artifacts)中,比如基于bean validation的約束驗證器。不幸的是,只是大部分JSF組件,并非所有的,比如轉換器和驗證器就不行,盡管OmniFaces 1.6將支持這些特性,但最好是在Java EE 7中能夠開箱即用。

          此外,Java EE 7中的CDI也沒有考慮到JASPIC組件,在此之中注入操作將無法工作。即使http請求和會話在Servlet Profile SAM中可用,但是當SAM被調用時,相應的CDI作用域也不會被建立。這意味著它甚至不能通過bean管理器以編程方式來檢索請求或會話bean作用域。

          還有一種特殊情況是,各種各樣的平臺artifacts可以通過一些替代的注解(如@PersistenceUnit)來注入,但早期的注入注解(@Resource)仍然需要做很多事情,比如DataSource。即使Java EE 7中引入了artifacts(如任務調度服務),但也不得不通過“古老”的@Resource來注入,而不是通過@Inject。

          b. 基于CDI來實現和改造其他規范中的相關技術

          CDI絕對不應該只專注于在其他規范中已經解決的那些問題,其他規范還可以在CDI之上來實現它們各自的功能,這意味著它們可以作為CDI擴展。以Java EE 7中的JSF 2.2為例,該規范中的兼容CDI的視圖作用域可作為CDI擴展來使用,并且其新的flow作用域也可被立即實現為CDI擴展。

          此外,JTA 1.2現在也提供了一個CDI擴展,其可以聲明式地應用到CDI托管的bean中。此前EJB也提供了類似的功能,其背后技術也使用到了JTA,但是聲明部分還是基于EJB規范。在這種情況下,可以通過JTA來直接處理其自身的聲明性事務,但是這需要在CDI之上進行。

          盡管從EJB 3版本開始,EJB beans已經非常簡單易用了,同時還相當強大,但問題是:CDI中已經提供了組件模型,EJB beans只是另一個替代品。無論各種EJB bean類型有多么實用,但是一個平臺上有2個組件模型,容易讓用戶甚至是規范實現者混淆。通過CDI組件模型,你可以選擇需要的功能,或者混合使用,并且每個注解提供了額外的功能。而EJB是一個“一體”模式,在一個單一的注解中定義了特定的bean類型,它們之間可以很好地協同工作。你可以禁用部分不想使用的功能。例如,你可以關閉bean類型中提供的事務支持,或者禁用@Stateful beans中的passivation,或者禁用@Singleton beans中的容器管理鎖。

          如果EJB被當做CDI的一組擴展來進行改造,可能最終會更好。這樣就會只有一個組件模型,并且具有同樣有效的功能。

          這意味著EJB的服務,如計時器服務(@Schedule、@TimeOut )、@Asynchronous、 @Lock、@Startup/@DependsOn和@RolesAllowed都應該能與CDI托管的bean一起工作。此外,現有EJB bean類型提供的隱式功能也應該被分解成可單獨使用的功能。比如可以通過@Pooled來模擬@Stateless beans提供的容器池,通過@CallScoped來模擬調用@Stateless bean到不同的實例中的行為。

          2.  更深入的Pruning(修剪)和Deprecating(棄用)

          在Java EE平臺中,為數眾多的API可能會令初學者不知所措,這也是導致Java EE如此復雜的一個重要原因。因此從Java EE 6版本開始就引入了Pruning(修剪)和Deprecating(棄用)過程。在Java EE 7中,更多的技術和API成為了可選項,這意味著開發者如果需要,還可以包含進來。

          比如我個人最喜歡的是JSF本地托管bean設施、JSP視圖處理程序(這早在2009年就被棄用了),以及JSF中各種各樣的功能,這些功能在規范文件中很長一段時間一直被描述為“被棄用”。

          如果EJB組件模型也被修剪將會更好,但這有可能還為時過早。其實最應該做的是繼續去修剪EJB 2編程模型相關的所有東西,比如在Java EE 7中依然存在的home接口。

          3.  一個標準化的緩存API

          JCache緩存API原本將包含在Java EE 7中,但不幸的是,該API錯過了重要的公共審查的最后期限,導致其沒能成為Java EE 7的一部分。

          如果該規范能夠在Java EE 8計劃表的早期階段完成,就有可能成為Java EE 8的一部分。這樣,其他一些規范(如JPA)也能夠在JCache之上重新構建自己的緩存API。

          4.  所有管理對象(administrative objects)的應用內替代品

          Java EE中有一個概念叫“管理對象(administrative objects)”。這是一個配置在AS端而不是在應用程序本身中的資源。這個概念是有爭議的。

          對于在應用服務器上運行許多外部程序的大企業而言,這可以是一個大的優勢——你通常不會想去打開一個外部獲得的應用程序來改變它連接的數據庫的相關細節。在傳統企業中,如果在開發人員和操作之間有一個強大的分離機制,這個概念也是有益的——這可以在系統安裝時分別設置。

          但是,這對于在自己的應用服務器部署內部開發的應用程序的敏捷團隊來說,這種分離方式是一個很大的障礙,不會帶來任何幫助。同樣,對于初學者、教育方面的應用或者云部署來說,這種設置也是非常不可取的。

          從Java EE 6的@DataSourceDefinition開始,許多資源(早期的“管理對象”)只能從應用程序內部被定義,比如JMS Destinations、email會話等。不幸的是,這并不適用于所有的管理對象。

          不過,Java EE 7中新的Concurrency Utils for Java EE規范中有明確的選項使得它的資源只針對管理對象。如果在Java EE 8中,允許以一個便攜的方式從應用程序內部配置,那么這將是非常棒的。更進一步來說,如果Java EE 8中能夠定義一種規范來明確禁止資源只能被administrative,那么會更好。

          5.  綜合的現代化的安全框架

          在Java EE中,安全一直是一個棘手的問題。缺乏整體和全面的安全框架是Java EE的主要缺點之一,尤其是在討論或評估競爭框架(如Spring)時,這些問題會被更多地提及。

          并不是Java EE沒有關于安全方面的規定。事實上,它有一整套選項,比如JAAS、JASPIC、JACC、部分的Servlet安全方面的規范、部分EJB規范、JAX-RS自己的API,甚至JCA也有一些自己的安全規定。但是,這方面存在相當多的問題。

          首先,安全標準被分布在這么多規范中,且并不是所有這些規范都可以用在Java EE Web Profile中,這也導致難以推出一個綜合的Java EE安全框架。

          第二,各種安全API已經相當長一段時間沒有被現代化,尤其是JASPIC和JACC。長期以來,這些API只是修復了一些小的重要的問題,從來沒有一個API像JMS 2一樣被完整地現代化。比如,JASPIC現在仍然針對Java SE 1.4。

          第三,個別安全API,如JAAS、JASPIC 和JACC,都是比較抽象和低層次的。雖然這為供應商提供了很大的靈活性,但是它們不適合普通的應用程序開發者。

          第四,最重要的問題是,Java EE中的安全機制也遭遇到了“管理對象”中同樣的問題。很長一段時間,所謂的Java EE聲明式安全模型主要認證過程是在AS端按照供應商特定方式來單獨配置和實現的,這再次讓安全設置對于敏捷團隊、教育工作者和初學者來說成為一件困難的事。

          以上這些是主要的問題。雖然其中一些問題可以在最近的Java EE升級中通過增加小功能和修復問題來解決。然而,我的愿望是,能夠在Java EE 8中,通過一個綜合的和現代化的安全框架(盡可能地構建在現有安全基礎上)將這些問題解決得更加徹底。

          6.  平臺范圍內的配置

          Java EE應用程序可以使用部署描述文件(比如web.xml)進行配置,但該方法對于不同的開發階段(如DEV、BETA、LIVE等)來說是比較痛苦的。針對這些階段配置Java EE應用程序的傳統的方法是通過駐留在一個特定服務器實例中的“管理對象”來實現。在該方法中,配置的是服務器,而不是應用程序。由于不同階段會對應不同的服務器,因此這些設置也會隨之自動改變。

          這種方法有一些問題。首先在AS端的配置資源是服務器特定的,這些資源可以被標準化,但是它們的配置肯定沒有被標準化。這對于初學者來說,在即將發布的應用程序中進行解釋說明比較困難。對于小型開發團隊和敏捷開發團隊而言,也增加了不必要的困難。

          對于配置Java EE應用程序,目前有很多可替代的方式,比如在部署描述符內使用(基于表達式語言的)占位符,并使部署描述符(或fragments)可切換。許多規范已經允許指定外部的部署描述符(如web.xml中可以指定外部的faces-config.xml文件,persistence.xml中可以指定外部的orm.xml文件),但是沒有一個統一的機制來針對描述符做這些事情,并且沒有辦法去參數化這些包含的外部文件。

          如果Java EE 8能夠以一種徹底的、統一平臺的方式來解決這些配置問題,將再好不過了。似乎Java EE 8開發團隊正在計劃做這樣的事情。這將會非常有趣,接下來就看如何發展了。

          結論

          Java EE 8目前尚處于規劃初期,但愿上面提到的大多數特性能夠以某種方式加以解決。可能“無處不在的CDI”的幾率會大一些,此方面似乎已經得到了很大的支持,且事情已經在朝著這個方向發展了。

          標準化緩存API也非常有可能,它幾乎快被包含在Java EE 7中了,但愿其不會再次錯過規范審查的最后期限。

          此外,“現代化的安全框架”這一特性已經被幾個Java EE開發成員提到,但是此方面工作尚未啟動。這可能需要相當大的努力,以及大量其他規范的支持,這是一個整體性問題。順便說一句,安全框架也是Antonio Goncalves關于Java EE 7愿望清單中的第4個提議,希望Java EE 8可以解決這一問題。

          posted @ 2013-11-09 11:14 paulwong 閱讀(538) | 評論 (0)編輯 收藏

          安裝MONGODB在CENTOS、UBUNTU

          CENTOS
          http://docs.mongodb.org/manual/tutorial/install-mongodb-on-red-hat-centos-or-fedora-linux/


          UBUNTU
          http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/

          posted @ 2013-11-08 12:01 paulwong 閱讀(280) | 評論 (0)編輯 收藏

          Flume日志收集

               摘要: 一、Flume介紹Flume是一個分布式、可靠、和高可用的海量日志聚合的系統,支持在系統中定制各類數據發送方,用于收集數據;同時,Flume提供對數據進行簡單處理,并寫到各種數據接受方(可定制)的能力。設計目標:(1) 可靠性當節點出現故障時,日志能夠被傳送到其他節點上而不會丟失。Flume提供了三種級別的可靠性保障,從強到弱依次分別為:end-to-end(收到數據agent首先將event寫到...  閱讀全文

          posted @ 2013-10-31 18:20 paulwong 閱讀(51030) | 評論 (1)編輯 收藏

          MONGODB GUI客戶端

          WINDOWS+MAC+LINUX版的都有
          http://robomongo.org/

          posted @ 2013-10-27 11:29 paulwong 閱讀(489) | 評論 (0)編輯 收藏

          我是如何反編譯D-Link路由器固件程序并發現它的后門的

          OK,又是周末晚上,沒有約會,只有一大瓶Shasta汽水和全是快節奏的音樂…那就研究一下程序吧。

          一時興起,我下載了D-link無線路由器(型號:DIR-100 revA)的固件程序 v1.13。使用工具Binwalk,很快的就從中發現并提取出一個只讀SquashFS文件系統,沒用多大功夫我就將這個固件程序的web server(/bin/webs)加載到了IDA中:

          Strings inside /bin/webs

          /bin/webs中的字符信息

          基于上面的字符信息可以看出,這個/bin/webs二進制程序是一個修改版的thttpd,提供路由器管理員界面操作功能??雌饋硎墙涍^了臺灣明泰科技(D-Link的一個子公司)的修改。他們甚至很有心計的將他們很多自定義的函數名都輔以“alpha”前綴:

          Alphanetworks' custom functions

          明泰科技的自定義函數

          這個alpha_auth_check函數看起來很有意思!

          這個函數被很多地方調用,最明顯的一個是來自alpha_httpd_parse_request函數:

          Function call to alpha_auth_check

          調用alpha_auth_check函數

          我們可以看到alpha_auth_check函數接收一個參數(是存放在寄存器$s2里);如果alpha_auth_check返回-1(0xFFFFFFFF),程序將會跳到alpha_httpd_parse_request的結尾處,否則,它將繼續處理請求。

          寄存器$s2在被alpha_auth_check函數使用前的一些操作代碼顯示,它是一個指向一個數據結構體的指針,里面有一個char*指針,會指向從HTTP請求里接收到的各種數據;比如HTTP頭信息和請求地址URL:

          $s2 is a pointer to a data structure

          $s2是一個指向一個數據結構體的指針

          我們現在可以模擬出alpha_auth_check函數和數據結構體的大概樣子:

          struct http_request_t {     char unknown[0xB8];     char *url; // At offset 0xB8 into the data structure };  int alpha_auth_check(struct http_request_t *request);

          alpha_auth_check本身是一個非常簡單的函數。它會針對http_request_t結構體里的一些指針進行字符串strcmp比較操作,然后調用check_login函數,實際上就是身份驗證檢查。如果一旦有字符串比較成功或check_login成功,它會返回1;否者,它會重定向瀏覽器到登錄頁,返回-1;

          alpha_auth_check code snippet

          alpha_auth_check函數代碼片段

          這些字符串比較過程看起來非常有趣。它們提取請求的URL地址(在http_request_t數據結構體的偏移量0xB8處),檢查它們是否含有字符串“graphic/” 或 “public/”。這些都是位于路由器的Web目錄下的公開子目錄,如果請求地址包含這樣的字符串,這些請求就可以不經身份認證就能執行。

          然而,這最后一個strcmp卻是相當的吸引眼球:

          An interesting string comparison in alpha_auth_check

          alpha_auth_check函數中一個非常有趣的字符串比較

          這個操作是將http_request_t結構體中偏移量0xD0的字符串指針和字符串“xmlset_roodkcableoj28840ybtide”比較,如果字符匹配,就會跳過check_login函數,alpha_auth_check操作返回1(認證通過)。

          我在谷歌上搜索了一下“xmlset_roodkcableoj28840ybtide”字符串,只發現在一個俄羅斯論壇里提到過它,說這是一個在/bin/webs里一個“非常有趣”的一行。我非常同意。

          那么,這個神秘的字符串究竟是和什么東西進行比較?如果回顧一下調用路徑,我們會發現http_request_t結構體被傳進了好幾個函數:

          call_graph

          事實證明,http_request_t結構體中處在偏移量 0xD0處的指針是由httpd_parse_request函數賦值的:

          Checks for the User-Agent HTTP header

          檢查HTTP頭信息中的User-Agent值

          Populates http_request_t + 0xD0 with a pointer to the User-Agent header string

          將http_request_t + 0xD0指針指向頭信息User-Agent字符串

          這代碼實際上就是:

          if(strstr(header, "User-Agent:") != NULL) {     http_request_t->0xD0 = header + strlen("User-Agent:") + strspn(header, " \t"); }

          知道了http_request_t偏移量0xD0處的指針指向User-Agent頭信息,我們可以推測出alpha_auth_check函數的結構:

          #define AUTH_OK 1 #define AUTH_FAIL -1  int alpha_auth_check(struct http_request_t *request) {     if(strstr(request->url, "graphic/") ||        strstr(request->url, "public/") ||        strcmp(request->user_agent, "xmlset_roodkcableoj28840ybtide") == 0)     {         return AUTH_OK;     }     else     {         // These arguments are probably user/pass or session info         if(check_login(request->0xC, request->0xE0) != 0)         {             return AUTH_OK;         }     }      return AUTH_FAIL; }

          換句話說,如果瀏覽器的User-Agent值是 “xmlset_roodkcableoj28840ybtide”(不帶引號),你就可以不經任何認證而能訪問web控制界面,能夠查看/修改路由器的 設置(下面是D-Link路由器(DI-524UP)的截圖,我沒有 DIR-100型號的,但DI-524UP型號使用的是相同的固件):

          Accessing the admin page of a DI-524UP

          訪問型號DI-524UP路由器的主界面

          基于HTML頁上的源代碼信息和Shodan搜索結果,差不多可以得出這樣的結論:下面的這些型號的D-Link路由器將會受到影響:

          除此之外,幾款Planex路由器顯然也是用的同樣的固件程序:

          你很酷呀,D-Link。

          腳注:萬 能的網友指出,字符串“xmlset_roodkcableoj28840ybtide”是一個倒序文,反過來讀就是 “editby04882joelbackdoor_teslmx”——edit by 04882joel backdoor _teslmx,這個后門的作者真是位天才!

          posted @ 2013-10-26 09:33 paulwong 閱讀(257) | 評論 (0)編輯 收藏

          僅列出標題
          共115頁: First 上一頁 59 60 61 62 63 64 65 66 67 下一頁 Last 
          主站蜘蛛池模板: 胶南市| 轮台县| 社会| 冀州市| 修武县| 榆林市| 剑阁县| 汶上县| 洛扎县| 阳原县| 兖州市| 平远县| 临武县| 平安县| 西贡区| 泾源县| 米泉市| 山阳县| 石台县| 泉州市| 平谷区| 宝坻区| 镇雄县| 徐闻县| 杭锦旗| 鸡西市| 贵德县| 丹江口市| 托克托县| 桂阳县| 若羌县| 铁岭县| 湟中县| 东城区| 诸城市| 都江堰市| 榆林市| 大港区| 贵南县| 五峰| 隆化县|