- Windows: %WINDOWS%/system/drivers/etc/hosts
- Linux / Unix / OS X: /etc/hosts
marți, 1 decembrie 2009
Cum ne configuram mediul de development?
miercuri, 2 septembrie 2009
Python Decorators
luni, 24 august 2009
Richfaces and JQuery
In functiile javascript, daca aveti nevoie de functionalitati JQuery, folositi functia jQuery(.....) in loc de $(...). In aceasta maniera orice conflict dintre jQuery si prototype este rezolvat.
miercuri, 19 august 2009
Python SQLAlchemy ORM
1. In fisierul __init__.py am ales sa instantiez dependentele sqlalchemy ce vor fi folosite in fiecare entitate.
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
BaseEntity = declarative_base()
strDbURL = "oracle://db_tes:xxx@xe"
objDbEngine = create_engine(strDbURL, echo=False)
Session = sessionmaker(bind=objDbEngine)
Session.configure(bind=objDbEngine)
def getConnection():
return Session()
In acest moment putem incepe sa implementam entitatile. Fiecare entitate va extinde BaseEntity. De fiecare data cand vrem sa obtinem o conexiune la baza de date utilizam metoda getConnection(). O sessiune SQLAlchemy este asemanatoare cu o sesiune Hibernate.
2. Definim o clasa utilizator care are ca si cheie primara(username si parola --- nu faceti asa in practica: puteti alege cnp-ul ca metoda de identificare). Aici vreau doar sa demonstrez utilizarea cheilor compozite.
from da import BaseEntity
from sqlalchemy import Column,Integer,String,Numeric,DateTime,ForeignKey,Sequence
from sqlalchemy.orm import relation, backref
class User(BaseEntity):
username = Column("username", String, primary_key=True)
password = Column("password", String, primary_key=True)
descriere = Column("descriere", String)
def __init__(self, strUsername, strPassword, strDesc):
self.username = strUsername
self.password = strPassword
self.descriere = strDesc
3. In continuare implementam clasa adresa.
from da import BaseEntity
from sqlalchemy import Column,Integer,String,Numeric,DateTime,ForeignKey,Sequence
from sqlalchemy.orm import relation, backref
class Adress(BaseEntity):
id = Column("id", Integer, Sequence("seq_xxx_id"), primary_key=True)
fk_username = Column("fk_username", String, ForeignKey("utilizatori.username"))
fk_password = Column("fk_password", String, ForeignKey("utilizatori.password"))
street = Column("street", String)
number = Column("number", String)
user = relation("User",
foreign_keys=[fk_username, fk_password],
primaryjoin="User.username == Address.fk_username and "
"User.password == Address.fk_password",
backref="adresses")
def __init__(self, strUser, strPasswd, strStreet, strNumber):
self.fk_username = strUser
self.fk_password = strPassword
self.street = strStreet
self.number = strNumber
Observatii: in acest exemplu incerc sa demonstrez puterea si flexibilitatea pe care o ofera SQLAlchemy. In primul rand, in orice entitate SQLAlchemy vom defini structura tabelei mapata la atribute ale entitatii. Utilizarea functiei relation permite implementarea legaturilor de tip one-to-one, one-to-many si many-to-many. De asemenea, utilizarea argumentului keyword backref indica frameworkului sa adauge automat un atribut la capatul celalalt al relatiei.
4. Dupa ce am implementat toate entitatile trebuie sa le si folosesc. In exemplul de mai jos arata o succesiune de linii de cod care demonstreaza functionalitatea entitatilor.
import da
from da import User, Address
# query pentru a selecta toti utilizatorii din bd
objSes = da.getConnection()
for objUsr, in objSes.query(User).all():
print(objUsr.addresses)
# query pentru a conditiona returnarea unui utilizator care are o anumita adresa
for objUsr in objSes.query(User, Address).filter(User.username == Address.fk_username and User.password == Address.fk_password).filter(Address.id == 1).all():
print(objUsr.username)
In concluzie, SQLAlchemy faciliteaza maparea tabelelor in logica obiect(la fel ca orice ORM) dar nu necesita un fisier de configurare separat sau anotari suplimentare(precum Hibernate). De asemenea, scrierea de query-uri este extrem de usoara. Ceea ce nu s-a aratat dar este intuitiv este adaugare de noi entitati in bd. Pentru aceasta folositi objSes.add(objInstance). Folositi add chiar daca vreti sa faceti update(SQLAlchemy va sti ce doriti sa faceti in functie de atributele setate in instanta).
vineri, 7 august 2009
Java si mocking - PowerMock
- mock pentru functii statice
- mock pentru functii private
class Calculator {
public static int add(int a1, int a2) {
return a1 + a2;
}
}
class Operatii {
public int operatieComplexa(int a1, a2) {
int a = Calculator.add(a1, a2);
return ++a;
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest({Calculator.class})
class TestOperatii {
@Test
public void testOperatieComplexa() {
PowerMock.mockStatic(Calculator.class);
EasyMock.expect(Calculator.add(1, 2).andReturn(3);
PowerMock.replayAll();
Operatii obj = new Operatii();
int ret = obj.operatieComplexa(1, 2);
PowerMock.verifyAll();
Assert.assertEquals(4, ret);
}
}
Asta e tot. In momentul in care se executa testul in loc sa se foloseasca metoda statica add din clasa Calculator se foloseste o metoda injectata. Cateva elemente interesante sunt enumerate mai jos:
- @RunWith(PowerMockRunner.class). Indica JUnit sa foloseasca clasa PowerMockRunner pentru rularea testelor(nu merge fara asta datorita faptului ca PowerMock implementeaza un class loader custom).
- @PrepareForTest({Calculator.class}). In aceasta anotare se enumera clasele pentru care se va face mockStatic.
miercuri, 29 iulie 2009
Python si servicii web
------------------------------------------------------------------------------------------------
import httplib
HOST = "www.infovalutar.ro"
URL = "/curs.asmx"
def SOAP_GetMoneda(strMoneda):
strReq = """<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<getlatestvalue xmlns="http://www.infovalutar.ro/">
<Moneda>%s</Moneda>
</getlatestvalue>
</soap12:Body>
</soap12:Envelope>"""
return strReq % strMoneda
if __name__ == "__main__":
data = SOAP_GetMoneda("USD")
dctHeaders = {"Host" : HOST,
"Content-Type" : "text/xml; charset=utf-8",
"Content-Length" : len(data),
"SOAPAction" : "http://www.infovalutar.ro/getlatestvalue"}
con = httplib.HTTPConnection(HOST)
con.request("POST", URL, data, dctHeaders)
resp = con.getresponse()
print(resp.read())
con.close()
------------------------------------------------------------------------------------------------
Ceea ce nu se arata in acest exemplu este modul in care se parseaza raspunsul. Apelul resp.read() returneaza un string care reprezinta un document xml. Parsarea raspunsului nu este prezentata aici intrucat nu acesta este scopul articolului. Acelasi rezultat poate fi obtinut si prin utilizarea bibliotecilor urllib si urllib2, dar in momentul de fata httplib este libraria recomandata.
luni, 27 iulie 2009
JSF si localizarea
1. Se creeaza doua fisiere de resurse(limba engleza si limba romana)
In fiecare dintre ele se adauga o cheie lbWelcome=........ cu textul in engleza, respectiv romana.
2. se modifica fisierul faces-config.xml pentru a indica limbile suportate pentru localizare.
<application>
<locale-config>
<default-locale>ro< /default-locale>
<supported-locale>ro< /supported-locale>
<supported-locale>en< /supported-locale>
< / locale-config>
< /application>
3. Se creeaza o pagina jsp pentru pentru prezentarea continutului.
<%@page pageEncoding="UTF-8" contentType="text/html; charset=ISO-8859-2" %>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<f:view>
<
<h:commandLink action="#{languageBean.changeLanguage}" value="Romana">
<f:param name="lang" value="ro">
< /h:commandLink>
|
<h:commandLink action="#{languageBean.changeLanguage}" value="English">
<f:param name="lang" value="en">
< /h:commandLink><>
<h:outputText value="#{msg.lbWelcome}">
</h:form>
</f:view>
4. Se creeaza un backbean in care implementez metoda de schimbare limba.
package ro.testlocalization.traduceri;
import java.util.Locale;
import java.util.Map;
import javax.faces.application.Application;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
public class LanguageBean {
public void changeLanguage() {
Map req = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String lang = req.get("lang").toString();
Locale newLocale = new Locale(lang);
FacesContext context = FacesContext.getCurrentInstance();
context.getViewRoot().setLocale(newLocale);
}
}
5. Se mapeaza backbean-ul in faces-config.xml
6. Asta e tot. In acest moment ar trebui sa puteti rula aplicatia si sa puteti schimba limba de afisare a mesajului.
marți, 30 iunie 2009
Servicii web cu jax-ws: Partea 2
@Entity
public class Persoana {
@Id
private long cnp;
@OneToMany(mappedBy="parinte")
private List
//metode getter/setter
}
public class PersoanaWrapper implements Serializable {
private long cnp;
private PersoanaWrapper[] rude;
//metode getter/setter
}
Metoda din webservice care doreste sa returneze o persoana ar putea fi implementat de maniera urmatoare:
public PersoanaWrapper getPersoana(long cnp) {
//cod prin care incarc ejb-ul persoanei dorite. => Persoana persEJB;
PersoanaWrapper pers = new PersoanaWrapper();
int nrRude = persEJB.getRude().size();
pers.setCNP(persEJB.getCNP());
pers.setRude(new PersoanaWrapper[nrRude]);
for(int i = 0; i < nrRude; i++) {
PersoanaWrapper tmp = new PersoanaWrapper();
tmp.setCNP(persEJB.getRude().get(i).getCNP());
pers.getRude()[i] = tmp;
}
return pers;
}
O imbunatatire vizibila a codului de mai sus este reprezentata de adaugarea unei metode/constructor de copiere: "valueOf". Utilizand clase wrapper, puteti sa returnati orice tip de date doriti.
S-a mentionat intr-un post anterior ca in momentul in care un serviciu web este deployat in container el va fi expus si ca Session bean. Este recomandat totusi sa accesati serviciul ori ca session bean ori ca web service(de preferat web service) pentru a fi sigur ca toate metodele sunt functionale.
Cum pot injecta resursa in serviciul web?
De cele mai multe ori este nevoie sa interactionam intr-un fel cu un sistem backend(o baza de date, un fisier txt, etc..) Pentru acest lucru, in Java EE exista PersistenceContext. Contextul de persistenta poate fi injectat usor utilizand urmatoarele linii de cod:
@PersistenContext(unitName="myPersistence")
private EntityManager em;
Contextul de persistenta nu este singura resursa care poate fi injectata intr-un serviciu web. Alte resurse pot fi de asemenea injectat. De exemplu un mail session sau un datasource(pentru bd). Presupun ca avem un DataSource mapat ca: java:jdbc/MyDS. Pentru a-l face disponibil in cod este suficient sa folosesc urmatoarea constructie:
@Resource(mappedName="java:jdbc/MyDS")
private DataSource ds;
Se procedeaza analog pentru orice fel de resursa doriti sa injectati. Intr-un post urmator voi arata cateva strategii pentru securizarea unui serviciu web.
luni, 29 iunie 2009
Servicii web cu jax-ws: Partea 1
Obs: !!!!!!!!!Daca utilizati jre/jdk 6 downloadati versiune de jboss compilata pentru java 6. Astfel nu veti putea accesa serviciile web, in mare parte datorita unui conflict din saaj.jar din jboss si saaj.jar din jdk 6.
Acum vom presupune ca aveti versiunea corecta de jboss pe calculatorul dumneavoastra. Java EE/jax-ws usureaza foarte mult dezvoltarea de servicii web.
@WebService
@SOAPBinding(style=Style.RPC)@Stateless
public interface ServiciuTest {
@WebMethod
public String sayHello(@WebParameter(name="message")String msg);
}
@StatelessAsta e tot ce trebuie sa faceti pentru a avea un serviciu web functional. In acest moment serviciul poate fi deployat pe un container care suporta jax-ws. In Java EE serviciul de mai sus va fi expus atat ca serviciu web cat si ca un session bean. Interfata reprezinta de fapt o specificatie pentru serviciul web(endpoint). Retineti faptul ca nu veti putea returna obiecte care nu sunt serializabile.
@WebService(endpointInterface="ServiciuTest")
public class ServiciuTestBean {
public String sayHello(String msg) {
return msg;
}
}
In continuare voi arata cum se poate implementa un serviciu web care transmite un fisier.
@WebService
@SOAPBinding(style=Style.RPC)@Stateless
public interface ServiciuFilesTest {
@WebMethod
public byte[] getFile(@WebParam(name="file_name")String fName);
}
@Statelesspublic byte[] getFile(String fName) {
@WebService(endpointInterface="ServiciuFilesTest")
public class ServiciuFilesTestBean {
byte[] deRet = new byte[(int)(new File(fName)).length()];return deRet;
try {
FileInputStream file = new FileInputStream(fName);
file.read(deRet);
file.close();
}
catch(IOException ioe) {
ioe.printStackTrace();
return null;
}
}
}
Asta e tot. In acest fel putem trimite fisiere de la webservice catre un client. De obicei este recomandat sa encodam continutul trimis in Base64 pentru a garanta faptul ca nu vor aparea probleme.
Scenariul in care am folosit abordarea de mai sus a fost urmatorul: clientul web face o cerere pentru un document(dupa id ci nu dupa cale absoluta). Serviciul web interogheaza baza de date, citeste continutul si il returneaza catre clientul web. Acesta salveaza continutul local si il afiseaza in interfata.
Intr-un post ulterior voi arata cum putem returna date complexe printr-un serviciu web si cum putem folosi injectarea resurselor(specific pentru Java EE).
joi, 4 iunie 2009
java.util.logging si o clasa de logare
- info
- warning
- error
package ro.example;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.logging.*;
public class LoggerSingleton {
private static Logger logger;
private static LoggerSingleton selfInst = null;
private String msgFile = "err%s.log";
private LoggerSingleton() throws Exception {
logger = Logger.getLogger("MyApplication");
this.switchStdErr(this.msgFile);
}
/**
* Metoda folosita pentru a schimba stderr(standard error stream)
* @param fName
* @throws Exception
*/
private void switchStdErr(String fName) throws Exception {
Calendar cal = GregorianCalendar.getInstance();
String file = String.format(fName, cal.get(Calendar.YEAR) + "-" + cal.get(Calendar.MONTH) + "-" + cal.get(Calendar.DAY_OF_MONTH));
PrintStream err = new PrintStream(new FileOutputStream(file, true));
System.setErr(err);
}
public static LoggerSingleton getInstance() throws Exception {
if(selfInst == null)
selfInst = new LoggerSingleton();
return selfInst;
}
/**
* Metoda folosita pentru a scrie un mesaj de tip info
* @param msg
*/
public void writeInfo(String msg) {
try {
logger.log(Level.INFO, msg);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
/**
* Metoda folosita pentru a scrie un warning
* @param msg
*/
public void writeWarning(String msg) {
try {
logger.log(Level.WARNING, msg);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
public void writeWarning(Exception excp) {
try {
logger.log(Level.WARNING, excp.getMessage(), excp);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
/**
* Metoda folosita pentru a loga un mesaj de eroare.
* @param msg
*/
public void writeError(String msg) {
try {
logger.log(Level.SEVERE, msg);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
public void writeError(Exception excp) {
try {
logger.log(Level.SEVERE, excp.getMessage(), excp);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
}
Obs: Metoda log din class Logger scrie mesajele in System.err. Din acest motiv primul lucru pe care il fac este sa redirectionez System.err catre fisierul dorit.
In continuare arat un posibil fisier de test care utilizeaza toate metodele disponibile.
package ro.example;
/**
* @author Radu Viorel Cosnita
* Doar testez logarea fiecarui tip de mesaj definit in logger singleton.
*/
public class TestLoggerSingleton {
public static void main(String[] args) throws Exception {
LoggerSingleton log = LoggerSingleton.getInstance();
log.writeInfo("Doar ca sa ma amuz");
log.writeWarning("Doar un warning");
log.writeError("Doar un mesaj de eroare");
try {
throw new Exception("O eroare draguta");
}
catch(Exception ex) {
log.writeWarning(ex);
log.writeError(ex);
}
}
}
Rezultatul obtinut a fost generarea unui fisier numit: err2009-5-4.log cu urmatorul continut:
Jun 4, 2009 3:27:01 PM ro.example.LoggerSingleton writeInfo
INFO: Doar ca sa ma amuz
Jun 4, 2009 3:27:01 PM ro.example.LoggerSingleton writeWarning
WARNING: Doar un warning
Jun 4, 2009 3:27:01 PM ro.example.LoggerSingleton writeError
SEVERE: Doar un mesaj de eroare
Jun 4, 2009 3:27:01 PM ro.example.LoggerSingleton writeWarning
WARNING: O eroare draguta
java.lang.Exception: O eroare draguta
at ro.example.TestLoggerSingleton.main(TestLoggerSingleton.java:16)
Jun 4, 2009 3:27:01 PM ro.example.LoggerSingleton writeError
SEVERE: O eroare draguta
java.lang.Exception: O eroare draguta
at ro.example.TestLoggerSingleton.main(TestLoggerSingleton.java:16)
In fiecare zi in care se executa/invoca metode din clasa TestLoggerSingleton va fi generat un log separat. Aceasta abordare permite urmarirea evolutiei aplicatie intr-o maniera extrem de simpla. Intr-un post viitor voi arata cum se poate genera un log in format xml in log de plaintext.
luni, 1 iunie 2009
Hibernate session and web application
public class ManageConexiune implements Filter {
private FilterConfig filterConfig;
public void destroy() {}
public void init(FilterConfig fConfig) {
this.filterConfig = fConfig;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
Object obj = request.getAttribute("OPENED_CONNECTION");
Session ses = null;
if(obj != null) {
ses = (Session)obj;
try {
ses.close();
}
catch(HibernateException ex) {
ex.printStackTrace(); //just print the stack trace into log files
}
}
ses = HibernateSingleton.getInstance().openSession();
request.setAttribute("OPENED_CONNECTION", ses);
chain.doFilter(request, response);
}
}
Obs: Clasa HibernateSingleton pune la dispoziție două metode statice: una din ele este getInstance care returneaza un SessionFactory. Cea de a doua metodă statică nu face altceva decât să returneze sesiunea deschisă de pe request.
public class HibernateSingleton {
private static SessionFactory sessionFactory;
static
{
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
}
public static SessionFactory getInstance()
{
return sessionFactory;
}
public static Session getRequestSession() {
return (Session)Contexts.getRequest().getAttribute("OPENED_CONNECTION");
}
}
Astfel, ori de câte ori aveți nevoie de o sesiune validă invocați HibernateSingleton.getRequestSession. Utilizând maniera deschisă aici veți evita multe erori de genul Can't open connection sau Session closed. De asemenea, veți simți o îmbunătățire a performanțelor site-ului și veți obține timpi de acces mai buni.
miercuri, 20 mai 2009
Python mocking __new__
class TestedClass(float):
def mockedNew(cls, *args, **kwds):
print("Mocked new")
self = float.__new__(*args, **kwds)
return self
def deleteNew(cls):
cls.__new__ = cls.mockedNew
def __new__(cls, arg=0.0):
"Convert from inch to meter"
print("Normal new")
return float.__new__(cls, arg*0.0254)
def __init__(self, arg=0.0):
print("Not working")
deleteNew = classmethod(deleteNew)
mockedNew = classmethod(mockedNew)
if __name__ == "__main__":
TestedClass.deleteNew()
print(TestedClass(12))
In mod normal, in exemplul de mai sus, daca nu as apela deleteNew rezultatul ar fi:
- Normal new
- Not working
- 0.3048
- Mocked new
- Not working
- 12
marți, 19 mai 2009
Python si Mocker
def algoritm_complex(objOpen=open):
#aici vine rularea algoritmului
#aici vine partea de dependenta de hdd
f = objOpen("fisier.txt", "w")
f.write("testare simpla")
f.close()
Observam ca in functia de mai sus am furnizat un parametru cu valoare default buitin-ul open. In aceasta maniera in momentul in care functia va fi apelata intr-un mediu de productie nu va fi furnizat nici un parametru in timp ce in momentul in care se va dori testarea algoritmului se fa furniza o functie simulata. In continuare prezint partea de "mocking":
def test_AlgoritmComplex():
controller = Mocker()
objOpen = controller.mock()
fMocked = controller.mock()
objOpen.open("fisier.txt", "w")
controller.result(fMocked)
fMocked.write("testare simpla")
fMocked.close()
controller.replay()
algoritm_complex(objOpen.open)
Asta e tot ce aveti nevoie. Daca functia ar fi returnat un rezultat puteati face un assert pe valoarea returnata doar ca sa va asigurati ca algoritmul a functionat asa cum ati dorit. Pentru mai multe informatii despre acest mod de testare, vizitati site-ul http://labix.org/mocker.
joi, 7 mai 2009
Python si metod statice
In Java, o metoda statica se implementeaza in felul urmator:
public static void helloWorld() { System.out.println("Salutari"); }
In python lucrurile sunt mai complicate si depinde si de versiune folosita. De exemplu, daca folosim o versiune de python anterioara 2.4 atunci vom defini o metoda statica in felul urmator:
def helloWorld(cls):
print("Salutari")
helloWorld = classmethod(helloWorld)
Daca folosim o versiune mai noua de python lucrurile se simplifica deoarece putem folosi un decorator.
@staticmethod
def helloWorld(cls):
print("Salutari")
In ambele cazuri lucrurile sunt mai putin lizibile decat in Java. Oricum, asta este modul de a defini/folosi functii/metode statice in Python.
marți, 21 aprilie 2009
Richfaces panelMenu
Pasul 1: Se creaza o solutie eclipse de tip Dynamic Web Project versiunea 2.5 si se activeaza JSF 1.2. De asemenea,trebuie sa faceti disponibil framework-ul richfaces asa cum este descris la adresa: http://www.jboss.org/file-access/default/members/jbossrichfaces/freezone/docs/devguide/en/html_single/index.html.
Pasul 2: Se creaza un fisier .jsp si se adauga urmatorul cod:
<%@page pageEncoding="UTF8" contentType="text/html; charset=ISO-8859-2" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://richfaces.org/a4j" prefix="a4j" %>
<%@ taglib uri="http://richfaces.org/rich" prefix="rich" %>
<f:view>
<h:form>
<rich:panelmenu event="onclick" mode="ajax" width="300">
<rich:panelmenugroup label="Meniu test">
<rich:panelmenuitem label="Optiune 1" onclick="window.location.href='test.jsf';">
<rich:panelmenuitem label="Optiune 2" onclick="window.location.href='test.jsf';">
<rich:panelmenuitem label="Optiune 3" onclick="window.location.href='test.jsf';">
</rich:panelMenuGroup>
</rich:panelMenu>
</h:form>
</f:view>
Observatii:
In acest momentant ati obtinut un meniu flotant dar fara nici un fel de functionalitate alta decat fold. De cele mai multe ori veti avea nevoie sa faceti redirectare catre o alta pagina. Cel mai usor este sa folositi: onclick attribute si cod javascript pentru redirectionare. Acestea fiind lamurite ar mai fi de mentionat ce reprezinta: event="onclick" mode="ajax".
Onclick indica framework-ului richfaces sa genereze un meniu flotant care sa faca fold doar in momentul in care se executa click. O alta varianta ar putea fi onmouseover. A doua obtiune tine de modul in care se face submit. Modul predefinit este "server" ceea ce inseamna ca la fiecare click se va face refresh la pagina si se va reface arborele JSF. De asemenea, ca orice componenta din JSF se poate face bind pentru a se face legatura cu un backbean. Tipul de date este de forma: "HtmlPaneMenuXXXXX" unde xxx este: {"", "Group", "Item"}. Pachetul pentru acest tip de date este: org.richfaces.component.html. In acest pachet veti gasi majoritatea componentelor din RichFaces.
luni, 6 aprilie 2009
Configurare subversion + apache2 + ldap
Pe parte de ldap, vom presupune ca avem urmatoarea structura:
dc=example,dc=com
ou=Groups,dc=example,dc=com
cn=group_svn_repo,ou=Groups,dc=example,dc=com
ou=Users,dc=example,dc=com
cn=user1,ou=Users,dc=example,dc=com
cn=user2,ou=Users,dc=example,dc=com
In mod normal asta e tot ce aveti nevoie inainte de configurare apache. Pe scurt, logica este sa facem autentificare pe nodul de users dupa care verificam daca utilizatorul este in grupul specificat. Aici se va descrie configurarea in virtual host, intrucat este cea mai raspandita.
ServerName svn1.example.com
ServerAdmin rcosnita@example.com
ErrorLog /var/log/apache2/error_svn.log
CustomLog /var/log/apache2/access_svn.log combined
DAV svn
SVNPath /svn/repos/repo_virtual/
SVNListParentPath on
AuthBasicProvider ldap
AuthType Basic
AuthName "Example server"
AuthzLDAPAuthoritative off
AuthLDAPURL ldap://svn1.example.com:389/OU=Users,DC=informatix,DC=ro?cn?sub
AuthLDAPBindDN CN=root,DC=example,DC=com
AuthLDAPBindPassword parolamea
AuthLDAPGroupAttribute member
AuthLDAPGroupAttributeIsDN on
Require group cn=group_svn_repo,ou=Groups,dc=informatix,dc=ro
Asta e tot ce trebuie sa faceti. Dupa ce ati terminat dati un restart la serverul de apache si totul ar trebui sa functioneze.
Este important sa tineti minte ca serverul apache face cache in momentul in care se conecteaza la ldap. Asta inseamna ca orice intrare care se adauga in ldap dupa ce apache este conectat nu va fi vazuta pana la restart-ul unuia dintre servere.
Dintr-un motiv care inca mi-e neclar, cand am folosit apache + openldap solutia de mai sus nu a functionat. Din acest motiv, am "trisat" si am adaugat fiecarui utilizator un atribut din schema ldap care sa semnifice grupul. In cazul meu acest atribut a fost labeledURI.
Dupa aceasta am inlocuit: Require group cn=group_svn_repo,ou=Groups,dc=informatix,dc=ro
cu: Require ldap-attribute labeledURI=cn=group_svn_repo,ou=Groups,dc=informatix,dc=ro.
Dupa aceasta modificare totul a functionat fara probleme.
Sper sa gasiti acest post interesant.
Cosnita Radu Viorel!
luni, 9 martie 2009
Configurare Apache2 si Tomcat 6 prin mod_proxy
joi, 22 ianuarie 2009
Configurare birt in mediul virtual hosts
In acest moment puteti folosi acest context. Asta e tot ce aveti de facut. Intr-un post viitor voi arata cum se pot creea virtual host-uri pentru tomcat.
Cosnita Radu Viorel!