2.1. fejezet, GlassFish 3.1.2.2 konfiguráció
Ez az oldal elavult
Memória kezelés beállítása
A szerver memória használatát beállíthatjuk a [glassfishRoot]/glassfish/domains/domain1/config/domain.xml fájlban. Módosítsuk a beállításokat az alábbiak szerint:
<jvm-options>-XX:MaxPermSize=2048M</jvm-options> <jvm-options>-XX:PermSize=256m</jvm-options> <jvm-options>-Xmx1024m</jvm-options>
Adatbázis kapcsolat kezelése
DataSource: com.mysql.jdbc.jdbc2.optional.MysqlDataSource
Ha a Glassfish indítása vagy újraindítása előtt bemásoljuk a mysql-connector-java-x.y.z-bin.jar-t (ahol az x,y,z a verziószámot jelöli) a glassfish/lib ill. a glassfish/domains/domain1/lib/ext/ könyvtárba, bővebb paraméterlistát kapunk a következő nézetben. Azonban vigyázzunk, mert az adatbázis url kétszer szerepel a listában. Az egyiket le kell törölni, hogy működjön az adatbázis elérésünk. (Az URL-t javaslom letörölni.)
Ha JavaSE-ből is szeretnénk elérhetővé tenni az adatbázist, a allow-non-component-callers tulajdonságot állítsuk true értékre. Ezt az újabb (GlassFish Server Open Source Edition 3.1.2.2 (build 5)) AppServer-ben a JDBC Connection Pools > [DataPool] > Advanced oldal alján megtaláljuk külön opcióként (Allow Non Component Callers néven).
E mellett a Java SE programhoz szükségünk lesz egy jndi.properties fájlra az src könyvtárban az alábbi tartalommal:
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory java.naming.factory.url.pkgs=com.sun.enterprise.naming java.naming.provider.url=jnp://localhost:1099
Persze ezt megcsinálhatjuk Java programban is:
roperties props = new Properties(); props.setProperty(“java.naming.factory.initial”, “com.sun.enterprise.naming.SerialInitContextFactory”); props.setProperty(“java.naming.factory.url.pkgs”, “com.sun.enterprise.naming”); props.setProperty(“java.naming.factory.state”, “com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl”); //Ez csak a távoli szerver eléréséhez kell. props.setProperty(“org.omg.CORBA.ORBInitialHost”, “127.0.0.1″); props.setProperty(“org.omg.CORBA.ORBInitialPort”, “3700″); InitialContext ctx = new InitialContext (props);
Az alkalmazásunkhoz hozzá kell adnunk az appserv-rt.jar fájlt, ami a [GlassFish]/glassfish/lib könyvtárba van, és ez az összes Glassfish könyvtárt beemeli a projektbe. Meggondolandó ez a lépés, mert emiatt túl nagyra nő az exportáláskor az újabb .jar fájl. Érdemes külön könyvtárba másoltatni a csomagokat, amik a serverből valók, és amiket kézzel adtunk hozzá a projekthez. A .jar fájl futtatásakor egy script-tel bemásolhatók a szerverről a csomagok a program indítása előtt. Ez azért is lényeges, mert a META-INF könyvtárba tárolt MANIFEST.MF tartalmazza a Class-Path mezőt, és a .jar futtatásakor ezt veszi figyelembe a Java, hiába adjuk meg -cp paraméterben a saját alkönyvtárainkat.
Ha magyar UTF-8 karakter kódolást szeretnénk beállítani, akkor a properties listába vegyük fel a következő tulajdonságokat:
useUnicode=true characterEncoding=UTF-8
Automatikus újrakapcsolódás paraméter nem biztos hogy kell, de beállítható:
autoReconnect=true AutoReconnectForPools=true
Ez esetben com.mysql.jdbc.exceptions.jdbc4.CommunicationsException keletkezik, ha időtúllépés miatt megszakad a kapcsolat. Néhány MySQL beállítás:
SET GLOBAL connect_timeout=30; SHOW VARIABLES LIKE 'connect_timeout'; SET GLOBAL wait_timeout=28800; SHOW VARIABLES LIKE 'wait_timeout'; SET NAMES utf8;
A realm és a JAAS
Konténer alapú autentikációra és adatforrás alkalmazására egy alkalmazás szervert használtam. A GlassFish adminisztrációs felületén hozzunk létre új adatforrásokat és saját jogosultság kezelőket (Realm). A konténer alapú autentikáció két részből áll: egy bejelentkezési ablakból, és több szabályból, amik az erőforrások hozzáférhetőségét szabályozzák.
web.xml:
<security-constraint> <web-resource-collection> <web-resource-name>admin</web-resource-name> <url-pattern>/admin/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>ROLE_ADMIN</role-name> </auth-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>user</web-resource-name> <url-pattern>/user/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>ROLE_ADMIN</role-name> <role-name>ROLE_USER</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>FORM</auth-method> <realm-name>myRealm</realm-name> <form-login-config> <form-login-page>/login.xhtml</form-login-page> <form-error-page>/login.xhtml?auth-error=true</form-error-page> </form-login-config> </login-config> <security-role> <role-name>ROLE_ADMIN</role-name> </security-role> <security-role> <role-name>ROLE_USER</role-name> </security-role>
glassfish-web.xml:
<security-role-mapping> <role-name>ROLE_ADMIN</role-name> <group-name>ADMIN</group-name> </security-role-mapping> <security-role-mapping> <role-name>ROLE_USER</role-name> <group-name>USER</group-name> </security-role-mapping>
A Glassfish admin felületén hozzunk létre jdbc pool-t (Resources > JDBC > JDBC connection pools), adatforrást (Resources > JDBC > JDBC Resources), majd egy új, adatbázis alapú jogosultság kezelőt (Configurations > Server-config > Security > Realms). A szerver naplózását a Configurations > server-config > Logger Settings menüpontban állítsuk részletesebbre. A Log Levels fülön a javax.enterprise.system.core.security értéket állítsuk ALL-ra.
A realm létrehozása előtt adatbázis táblákat is kell készítenünk:
REATE TABLE IF NOT EXISTS `postcarduser` ( `USER_ID` bigint(20) NOT NULL AUTO_INCREMENT, `admin` tinyint(1) NOT NULL, `emailAddress` varchar(255) COLLATE utf8_hungarian_ci DEFAULT NULL, `enabled` tinyint(1) NOT NULL, `password` varchar(255) COLLATE utf8_hungarian_ci NOT NULL, `username` varchar(255) COLLATE utf8_hungarian_ci NOT NULL, PRIMARY KEY (`USER_ID`), UNIQUE KEY `emailAddress` (`emailAddress`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci AUTO_INCREMENT=3 ; INSERT INTO `postcarduser` (`USER_ID`, `admin`, `emailAddress`, `enabled`, `password`, `username`) VALUES (1, 1, 'papp.zoltan@mx1.hu', 1, 'q', 'Papp Zoltán'), (2, 0, 'papp.zoltan@mx2.hu', 1, 'q', 'Papp Zoltán'); CREATE TABLE IF NOT EXISTS `usergroup` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `description` varchar(255) COLLATE utf8_hungarian_ci NOT NULL, `group_name` varchar(64) COLLATE utf8_hungarian_ci NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `group_name` (`group_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci AUTO_INCREMENT=3 ; INSERT INTO `usergroup` (`id`, `description`, `group_name`) VALUES (1, 'Adminisztrátor', 'ADMIN'), (2, 'Felhasználó', 'USER'); CREATE TABLE IF NOT EXISTS `user_join_group` ( `user_name` varchar(255) COLLATE utf8_hungarian_ci NOT NULL, `group_name` varchar(64) COLLATE utf8_hungarian_ci NOT NULL, PRIMARY KEY (`user_name`,`group_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci; INSERT INTO `user_join_group` (`user_name`, `group_name`) VALUES ('papp.zoltan@mx1.hu', 'ADMIN'), ('papp.zoltan@mx1.hu', 'USER'), ('papp.zoltan@mx2.hu', 'USER'); CREATE TABLE IF NOT EXISTS `v_active_user` ( `username` varchar(255) ,`password` varchar(255) ); DROP TABLE IF EXISTS `v_active_user`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_active_user` AS select `u`.`emailAddress` AS `username`,`u`.`password` AS `password` from `postcarduser` `u` where (`u`.`enabled` = 1);
A v_active_user és az alapadatok kivételével az installDB.jar létrehozza az összes felsorolt táblát.
Ha esetleg nem találnánk meg a Group Table User Name Column mezőt, vegyük fel tulajdonságként group-table-user-name-column néven. Ez a hiányosság az Eclipse Helios-hoz letöltött GlassFish Tools Bundle for Eclipse csomaghoz mellékelt Glassfish 3.1.0.0 verzióban jelentkezett.
A realm Digest Algorithm és Password Encryption Algorithm mezőit állítsuk none fejlesztés alatt, de produkciós környezetbe használjuk az MD5 vagy SHA-256 értéket.
(MS-SQL 2008-nál nem kell megadni az adatbázis előtagot a kepeslap.v_active_user és a kepeslap.user_join_group esetén. Realm változtatás után mindig indítsuk újra a Glassfish-t!)
A bejelentkező form a következő:
<form action="j_security_check" class="form" method="post"> <p class="email"> <input type="text" name="j_username" id="j_username"/> <label for="j_username">E-mail / Username</label> </p> <p class="pwd"> <input type="password" name="j_password" id="j_password" /> <label for="j_password">Password</label> </p> <p class="submit"> <input name="login" type="submit" value="Login" /> <input name="reset_pwd" type="submit" value="Reset Password"> </p> </form>
Fontos kiemelni itt a j_security_check, a j_username és a j_password szerepét. Ezek ugyanis a konténer felé indított POST eseményt és az átadott paraméterekket jelölik.
Java kódból a HTTPServletRequest osztály 3 metódusával érhető el a bejelentkezett felhasználó:
public String getRemoteUser(); public java.security.Principal getUserPrincipal(); public boolean isUserInRole(String abstractRole);
Bejelentkezett felhasználó kiléptetése:
import java.io.IOException; import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import javax.faces.context.FacesContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Logger; @ManagedBean(name="authBackingBean") @RequestScoped public class AuthBackingBean { private static Logger log = Logger.getLogger(AuthBackingBean.class.getName()); public void logout() { String result="/index.xhtml"; FacesContext context = FacesContext.getCurrentInstance(); HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest(); FacesContext facesContext = FacesContext.getCurrentInstance(); try { request.logout(); String url = facesContext.getApplication().getViewHandler().getActionURL(facesContext, result); facesContext.getExternalContext().redirect(url); } catch (ServletException e) { log.error("Failed to logout user!", e); facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Hiba a levél küldésénél", "Nincs érvényes levélkézbesítést nyújtó szerver konfigurálva.")); } catch (IOException ex) { log.error("FacesContext exception: ", ex); } } }
Példa a bejelentkezett felhasználó elérésére:
public User getLoggedInUser() { Object request = FacesContext.getCurrentInstance().getExternalContext().getRequest(); User result = null; if (request instanceof HttpServletRequest) { Principal user = ((HttpServletRequest) request).getUserPrincipal(); if (user != null) { List<User> userList = findByEmailAddress(user.getName(), true); if (userList.size()==1) { result = userList.get(0); } } } return result; }
MySQL adatbázis telepítése
install.sh
#!/bin/bash GLASSFISH_DIR="/home/pzoli/glassfish3" cp -r installDB_origin installDB_lib for i in `cat dirs.txt`; do jar_files="$GLASSFISH_DIR/$i.jar" cp -n $jar_files ./installDB_lib/ done path="$CLASSPATH:./installDB_lib/*" $JAVA_HOME/bin/java -cp $path -jar installDB.jar cat install-images.sql install-defaults.sql tables_mysql_innodb.sql view.sql>defaults.sql mysql --default-character-set=utf8 -u pzoli -p kepeslap<defaults.sql rm defaults.sql rm -r installDB_lib
JavaMail
JNDI-n keresztül elérhető levelező rendszerünk is. A beállítási paraméterekhez az alábbiakból válogathatunk:
mail.smtp.socketFactory.port: 465 mail.smtp.port: 465 mail.smtp.socketFactory.fallback: false mail.smtp.auth: true mail.smtp.password: <gmail_password> mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory
Ezek után a JavaMail Session elérése Java-ban:
public void createSession() throws NoSuchProviderException { Session session = null; try { InitialContext ctx = new InitialContext(); session = (Session) ctx.lookup("mail/kepeslap"); } catch (NamingException e) { new NoSuchProviderException(e.getLocalizedMessage()); } transport = session.getTransport(); MyTransportListener myTransportListener = new MyTransportListener(); transport.addTransportListener(myTransportListener); transport.addConnectionListener(myTransportListener); } public void connectTransporter() throws MessagingException { transport.connect(); } public void closeTransporterConnection() throws MessagingException { transport.close(); } public String sendMailOverSMTP(Map<String, String> params) throws AddressException, MessagingException { String result = params.get("defaultResult"); // Instantiate a message Message msg = new MimeMessage(session); // Set message attributes msg.setFrom(new InternetAddress(params.get("fromEmail"))); if (params.containsKey("isCCToMe") && params.get("isCCToMe").equalsIgnoreCase("true")) { msg.setRecipient(RecipientType.CC, new InternetAddress(params.get("senderEmail"))); } String recipientMailAddress = params.get("recipientMailAddress"); if ((recipientMailAddress != null) && !recipientMailAddress.isEmpty()) { msg.addRecipient(Message.RecipientType.TO, new InternetAddress(recipientMailAddress)); } msg.setSubject(params.get("subject")); msg.setSentDate(new Date()); // Set message content msg.setContent(params.get("mailContent"), "text/html; charset=UTF-8"); // msg.setText(mailStr); Address[] address; if (msg.getRecipients(Message.RecipientType.CC) != null) { address = ArrayHelper.join(msg.getRecipients(Message.RecipientType.TO), msg.getRecipients(Message.RecipientType.CC)); } else { address = msg.getRecipients(Message.RecipientType.TO); } // Send the message transport.sendMessage(msg, address); return result; }
Apache2 AJP és a Glassfish
Hogy Glassfist Apache-on keresztül elérhessük, két dolgot tehetünk. Engedélyezünk két modult:
sudo a2enmod proxy proxy_ajp
és beállítjuk az egyik site konfigurációba (pl.: 000-default) a proxy elérését:
<VirtualHost *:80> ... ProxyRequests off ProxyPass /kepeslap ajp://127.0.0.1:8009/kepeslap ... </VirtualHost>
Ezek után a Glassfish admin felületén a Configurations > server-config > Network Config > Network Listeners alatt létrehozunk egy jk-listener nevű, 8009 TCP porton figyelő kapcsolatot, ami továbbítja a kéréseket és válaszokat a két szerver között.
JNDI properties
Hibaelhárítás
PWC2785: Cannot serialize session attribute
Adminisztrációs felületen a Configurations > server-config > Web Container > Manager Properties ablakba állítsuk be a Session File Name tulajdonságot üres értékre, majd indítsuk újra a servert.
SEVERE: log4j:ERROR log4j called after unloading
Az egész hibaüzenet:
SEVERE: log4j:ERROR log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload. SEVERE: java.lang.IllegalStateException: Class invariant violation
Megoldás:
bin/asadmin create-system-properties org.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false
Többnyelvű paraméterek
Hibajelenség:
WARNING: PWC4011: Unable to set request character encoding to UTF-8 from context /, because request parameters have already been read, or ServletRequest.getReader() has already been called.
Használjuk a parameter-encoding tagot a glassfish-web.xml fájlban:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd"> <glassfish-web-app error-url=""> ... <parameter-encoding default-charset="UTF-8"/> ...
Arra ügyeljünk, hogy ha van property tag a fájlban (pl.: alternatedocroot_1), akkor az elé helyezzük a parameter-encoding tagot, különben hibát jelez a validátor.
Ajánlott olvasmányok:
- A hozzászóláshoz be kell jelentkezni