Upgrade to Pro — share decks privately, control downloads, hide ads and more …

FenixEdu Training Session Mar 2015

FenixEdu Training Session Mar 2015

Sérgio Silva

March 11, 2015
Tweet

Other Decks in Technology

Transcript

  1. Schedule Introduction Concepts Architecture Bennu Fenix Framework Struts & Renderers

    JSP & Renderers Faces & Spring New technologies Git & Maven Collaboration You are here
  2. FenixEdu • Academic Management System • Learning Management System •

    Open Source Project • https://github.com/FenixEdu • Used on several institutions
  3. FenixEdu Academic Management System Learning Management System Student Management Space

    Management Payments Infrastructure Alumni Candidatures Curriculum Management Grant Management Statistics Content Management System Homepages Online tests Communication
  4. Presentation Tier — Based on Struts Application Tier POJO’s Persistence

    Tier — Based on OJB XML Configuration Service Manager Services Filters XML Configuration DTO’s XML Configuration Data Repository JDBC JSP Views Actions SQL Statements
  5. The 11 “Simple” Steps 1. Create a POJO to represent

    the domain object; 2. Write the SQL schema to store the domain object; 3. Write the xml configuration to map the POJO against the SQL schema; 4. Write SQL statements for custom reading of the domain object (in case something other than a read by ID or a read all was necessary); 5. Create data transfer objects for passing information to the presentation tier; 6. Write services at the application level for creating, reading, updating and deleting the domain object; 7. Write access control filters to limit who can invoke services; 8. Write service and filter configurations in a xml file; 9. Create JSP views for presenting information to the users; 10. Write Actions to handle user requests; 11. Configure struts xml files to specify the application flow.
  6. Presentation Tier — Based on Struts Application Tier Persistence Tier

    — Fenix Framework Based Service Manager Services Filters XML Configuration Domain Objects XML Configuration Data Repository JDBC JSP Views Actions DML Configuration
  7. • Long compilation times • Large memory requirements • Poor

    expansibility • Poor encapsulation • It becomes easy to break domain constraints
  8. Persistence Tier — Fenix Framework Based Data Repository Fenix Application

    Request Controller Module 1 Presentation Tier Application Tier Domain Objects Module 2 Presentation Tier Application Tier Domain Objects ... Module N Presentation Tier Application Tier Domain Objects
  9. Fenix Framework Bennu Framework Bennu Core Bennu IO Bennu Scheduler

    Bennu Portal Bennu Renderers Bennu Spring Bankai Angular Persistence Web Infrastructure Presentation Application Modules FenixEdu (IST) FenixEdu Id Cards FenixEdu Academic
  10. [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ bennu-portal --- [INFO] org.fenixedu:bennu-portal:jar:3.1.0-SNAPSHOT [INFO]

    +- org.fenixedu:bennu-core:jar:3.1.0-SNAPSHOT:compile [INFO] | +- org.jasig.cas.client:cas-client-core:jar:3.3.1:compile [INFO] | \- org.antlr:antlr4-runtime:jar:4.2.2:compile [INFO] | +- org.abego.treelayout:org.abego.treelayout.core:jar:1.0.1:compile [INFO] | \- org.antlr:antlr4-annotations:jar:4.2.2:compile [INFO] +- org.fenixedu:fenixedu-commons:jar:1.0.1:compile [INFO] +- com.google.guava:guava:jar:17.0:compile [INFO] +- joda-time:joda-time:jar:2.3:compile [INFO] +- com.google.code.gson:gson:jar:2.2.4:compile [INFO] +- javax.ws.rs:javax.ws.rs-api:jar:2.0:compile [INFO] +- com.mitchellbosecke:pebble:jar:1.0.0:compile [INFO] | \- com.coverity.security:coverity-escapers:jar:1.1:compile [INFO] +- pt.ist:fenix-framework-core-api:jar:2.4.0:compile [INFO] | +- pt.ist:fenix-framework-core-dml:jar:2.4.0:compile [INFO] | | +- commons-lang:commons-lang:jar:2.6:compile [INFO] | | \- antlr:antlr:jar:2.7.7:compile [INFO] | +- javax.transaction:jta:jar:1.1:compile [INFO] | +- pt.ist.esw:advice-runtime:jar:1.8:compile [INFO] | \- org.jgroups:jgroups:jar:3.2.7.Final:compile [INFO] +- pt.ist:fenix-framework-core-consistency-predicates:jar:2.4.0:compile [INFO] | +- jvstm:jvstm-fenix:jar:1.4:compile [INFO] | \- pt.ist:fenix-framework-core-adt-bplustree:jar:2.4.0:compile [INFO] +- javax.servlet:javax.servlet-api:jar:3.0.1:provided [INFO] +- org.slf4j:slf4j-api:jar:1.7.5:compile [INFO] \- junit:junit:jar:4.11:test [INFO] \- org.hamcrest:hamcrest-core:jar:1.3:test
  11. Semantic Versioning • Major Version (2.0.0) • API Disruption •

    Minor Version (1.2.0) • New (backward-compatible) API • Revision (1.2.3) • Bug fixes and internal changes
  12. Schedule Introduction Concepts Architecture Bennu Fenix Framework Struts & Renderers

    JSP & Renderers Faces & Spring New technologies Git & Maven Collaboration You are here
  13. Fenix Framework Bennu Framework Bennu Core Bennu IO Bennu Scheduler

    Bennu Portal Bennu Renderers Bennu Spring Bankai Angular Persistence Web Infrastructure Presentation Application Modules FenixEdu (IST) FenixEdu Id Cards FenixEdu Academic
  14. Fenix Framework • Java Framework for applications that require transactional,

    persistent, rich domain models • Transparent persistency, strong consistency guarantees across multiple concurrent actors • Designed for modularity • No commitment with a particular backend • More Info • Confluence • Fenix Framework Page
  15. • Fenix Framework Core • Fenix Framework modules • We

    will use the Consistency Predicates module • Persistence backend • We will focus on JVSTM / MySQL
  16. Fenix Framework Core • Domain Modelling Language (DML) • Generated

    API • Domain Objects / Relations • Transactions API
  17. DML • Declarative Language used to reify the Domain Model

    • Classes, Slots, Relations, Roles, ValueTypes, Enums • Code is generated for each element • Modular, allows dependencies between DML files
  18. Classes • Syntax similar to a regular Java class •

    Can only contain fields • Allows slot options • Allows specifying visibility modifiers • Will generate User.java • Slot types?! public class User { protected String username (REQUIRED); protected String password; protected String salt; protected DateTime created; public LocalDate expiration; public String email; public Locale preferredLocale; }
  19. ValueTypes • Builtin: Primitives, Primitive Wrappers, String, Joda Time, byte[],

    Serializable, JSON, Enums • User-defined: Any type • Multiple aliases for the same type • Must externalise to one or more value types • MUST be immutable valueType java.util.Locale as Locale { externalizeWith { String toLanguageTag(); } internalizeWith forLanguageTag(); } OR valueType java.util.Locale as JsonLocale { externalizeWith { String getLanguage(); String getCountry(); } }
  20. Relations • Named first-class citizen • Relates two domain classes

    • Each role must have a name (unique for that type) • Multiplicity ranges • E.g.: 0..1, 1..*, 5..9 • Upper multiplicity determines relation type (to-one, to-many) relation SystemUsers { protected Bennu playsRole bennu { multiplicity 1..1; } protected User playsRole user { multiplicity *; } }
  21. Relation Listeners • Hooks that are notified whenever the relation

    is modified • Useful for ensuring constraints are maintained • Allows notifications before add, after add, before remove and after remove. static { Registration. getRelationShiftStudent(). addListener( new ShiftStudentListener()); }
  22. Generated API DML Declaration Generated Code public class User public

    class User extends User_Base protected String username protected String getUsername() protected void setUserName(String) protected Bennu playsRole bennu { multiplicity 1..1; } protected Bennu getBennu() protected void setBennu(Bennu) protected User playsRole user { multiplicity *; } protected Set<User> getUserSet() protected void addUser(User) protected void removeUser(User)
  23. DML - Remarks • NEVER touch the _Base classes •

    They are re-generated for each module, and depend on the underlying backend • Undefined behaviour if invoked outside a transactional context (Hint: NPE) • Each DomainObject has a unique External ID • Object equality determined by identity (i.e. equals 㱻 ==) • Serializable, stores the object’s ID
  24. Fenix Framework Core API • Transactions API • Runtime configuration

    and initialisation • Domain Object retrieval API • Defines backend API • Your code should not depend on this • FenixFramework class
  25. Transactions API • All operations on Domain Objects must occur

    within a transaction • Three different types of transactions: • Read-Only - Any write will throw a WriteOnReadError • Speculative Read - Write causes restart in full write • Write • Allows listeners and introspectors • Provide transaction-local storage
  26. Transactions API • Three different ways to declare transactions: •

    Manually - Begin, Commit, Rollback • FenixFramework.getTransactionManager().withTransaction(Callable<T>) • @Atomic methods • withTransaction or @Atomic preferred, as they handle conflicts by restarting the transaction, and take care of proper bookkeeping
  27. Transactions API public String doIt() { FenixFramework.getTransactionManager().begin(); try{ return “Hello”;

    } finally { FenixFramework.getTransaction().commit(); } } @Atomic(mode = TxMode.READ) public String doIt() { return “Hello”; } public String doIt() { return FenixFramework. getTransactionManager(). withTransaction(() -> return “Hello”); }
  28. Runtime Configuration • How to configure the Fenix Framework? •

    How does the Framework know what domain to consider when running the application?
  29. Runtime Configuration • When using the provided maven plugin, it

    is as simple as placing a file fenix-framework.properties on your final application • When it is first needed, the Framework will read the configuration file and start up automatically, taking all of the project’s dependencies as part of the domain
  30. Domain Object API • You created your domain model, with

    all its classes and relations. How can you get a reference to it? • The framework defines a special DomainRoot class. Invocations of FenixFramework.getDomainRoot() are guaranteed to always return the same instance DomainRoot ApplicationRoot A B
  31. Domain Object API • How to identify domain objects outside

    your application? • DomainObject.getExternalId() Returns a (unique) String representation of the object • FenixFramework.getDomainObject(String) Recovers the object by its ID. Results undefined if ID not returned by a call to getExternalId() • FenixFramework.isDomainObjectValid(DomainObject) determines whether the given object is still valid (i.e. is a proper reference, has not been deleted, etc)
  32. Consistency Predicates • Consistency predicates ensure that no write transaction

    can leave the domain in an inconsistent state • Programmer is responsible for specifying constraints on the domain • Two ways to specify Consistency Predicates
  33. Consistency Predicates public class Person extends Person_Base { (…) @ConsistencyPredicate

    public final boolean namesCorrectlyPartitioned() { final String fullName = getName(); final String familyName = getFamilyNames(); final String composedName = getGivenNames() + " " + familyName; return fullName.equals(composedName); } } public class User { protected String username (REQUIRED); protected String password; (…) } public class User_Base extends AbstractDomainObject { @ConsistencyPredicate public final boolean checkMultiplicityOfUsername() { return getUsername() != null; } }
  34. Consistency Predicates • All @ConsistencyPredicates are run before the commit

    of a write transaction manipulating the object • Any failed Consistency Predicate will cause the commit to fail, throwing a ConsistencyException.
  35. Backends • Backends provide the concrete implementation of the Transactional

    and Persistence Support • You should NEVER write code that depends on backends, as it is bound to change drastically, even between minor versions • Two kinds of backends: • In-memory: Useful for testing • Persistence backed: For production usage
  36. JVSTM • Java Versioned Software Transactional Memory • Built in-house

    • Based on the concept of Versioned Boxes, containing the history of an object’s value • Requires that every stored value is immutable • Changes can only occur within write transactions
  37. MySQL/MariaDB • Used to synchronize the STM across multiple instances

    of an application • Each Domain Object is stored as a row in the database • Tables organised per type hierarchy • Special FF$ tables are used for bookkeeping and metadata (Specially FF$DOMAIN_CLASS_INFO, which contains class information) • MySQL/MariaDB supported types are used natively when possible (i.e., time, blob)
  38. Bennu App Bootstrap Deploy configuration Menu Configuration User authentication REST

    server infrastructure Transactional IO Scheduling system Theming Internationalization Signalling Access Groups Indexing & searching
  39. Bennu • Provides web application facilites for Fenix Framework •

    Open Source • https://github.com/FenixEdu/bennu • https://confluence.fenixedu.org/display/BENNU/ Scheduling
  40. Bennu Scheduling • Add tasks to run on given intervals

    • Execute tasks on a system while running
  41. Schedule Introduction Concepts Architecture Bennu Fenix Framework Struts & Renderers

    JSP & Renderers Faces & Spring New technologies Git & Maven Collaboration You are here
  42. Fenix Framework Bennu Framework Bennu Core Bennu IO Bennu Scheduler

    Bennu Portal Bennu Renderers Bennu Spring Bankai Angular Persistence Web Infrastructure Presentation Application Modules FenixEdu (IST) FenixEdu Id Cards FenixEdu Core
  43. UI

  44. How do we make these work together? While keeping a

    consistent design across the application?
  45. Struts • Struts was already in place since the very

    beginning • Using Tiles (which is now Apache Tiles) to organize the application’s design • Struts entry point with custom controller
  46. Bennu Portal • UI Integration Framework • Uniform styling across

    the entire application • Dynamically change the theme of your application • Dynamic menu construction and rendering • Out of the box scaffolding for web applications
  47. Bennu Portal • Code declares what functionalities it exposes •

    Dynamic model built from declared functionalities • This allows for full customisation of the menu • Semantic URLs from the path in the tree • Catch: The same functionality can only be installed in a single place
  48. Custom Portal Backends • Integrating your favourite presentation technology is

    quite simple • Contributions welcome! • Functionality discovery • Mapping custom URLs to functionalities • Currently supported: Struts, Spring, JSF 1.x, Redirect, Forward
  49. Apache Struts 1.2 • Open-source web-application framework • EOL’ed in

    April 2013 • Model-View-Controller architecture • https://struts.apache.org/development/1.x/ • Grab it while you can, parts of the site are offline
  50. Apache Struts 1.2 • Based on the concept of Actions

    (Controller) • Actions are responsible for handling the request, and forwarding to the response • Typically another action or a JSP • Originally configured using XML • Extended for annotation-based configuration
  51. @StrutsFunctionality(app = StudentViewApp.class, path = "residence-payments", titleKey = "link.title.residencePayments") @Mapping(path

    = "/viewResidencePayments", module = "student") @Forwards(@Forward(name = "showEvents", path = "/student/residenceServices/showResidenceEvents.jsp")) public class ViewResidencePayments extends FenixDispatchAction { @EntryPoint public ActionForward listEvents(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception { Person person = getLoggedPerson(request); request.setAttribute("person", person); request.setAttribute("payedEntries", person.getPayments(ResidenceEvent.class)); return mapping.findForward("showEvents"); } }
  52. Actions • Module-aware • DispatchActions run the method provided in

    the parameters • FenixAction / FenixDispatchAction • getFromRequest, redirect, getDomainObject, addActionMessage, writeFile • Don’t put @Atomic annotations in handler methods!!
  53. Actions • Once you’re done with the request, how to

    show the correct page? • @Forward + mapping.findForward • new ActionForward(“/xpto.jsp”) • Handle the response manually • File download, custom redirects, complex forwards
  54. @StrutsFunctionality(app = StudentViewApp.class, path = "residence-payments", titleKey = "link.title.residencePayments") @Mapping(path

    = "/viewResidencePayments", module = "student") @Forwards(@Forward(name = "showEvents", path = "/student/residenceServices/showResidenceEvents.jsp")) public class ViewResidencePayments extends FenixDispatchAction { @EntryPoint public ActionForward listEvents(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception { Person person = getLoggedPerson(request); request.setAttribute("person", person); request.setAttribute("payedEntries", person.getPayments(ResidenceEvent.class)); return mapping.findForward("showEvents"); } }
  55. @StrutsFunctionality(app = StudentViewApp.class, path = "residence-payments", titleKey = "link.title.residencePayments") @Mapping(path

    = "/viewResidencePayments", module = "student") @Forwards(@Forward(name = "showEvents", path = "/student/residenceServices/showResidenceEvents.jsp")) public class ViewResidencePayments extends FenixDispatchAction { @EntryPoint public ActionForward listEvents(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception { Person person = getLoggedPerson(request); request.setAttribute("person", person); request.setAttribute("payedEntries", person.getPayments(ResidenceEvent.class)); return mapping.findForward("showEvents"); } }
  56. Action Form • Devilish way to handle user-input • Per-module,

    declared in the module’s XML file • In the @Mapping, you can choose the form for your action • Forms are populated from request parameters, and validated according to specific rules • Parameters are accessible in a map-like interface DON’T USE!
  57. Bennu Renderers • Our attempt at making Struts suck less

    • Two major components: • Struts modernisation / Portal Integration • Renderers Framework • No matter how hard we try, it’s still struts…
  58. Struts Integration • Modular, annotation-based struts configuration • @StrutsApplication /

    @StrutsFunctionality • “Security” features - A checksum is injected into every link in the response, and checked when the functionality is accessed • Parsers for multipart requests • Synchronisation between Struts and application locales
  59. Renderers • Taglib for automatic object visualisation/edition • Generates HTML

    code from Java objects • Able to render/edit both Domain Objects and POJOs
  60. Renderers • Two main parts: • Renderers know how to

    render an object of a given type. Can be both for input and output • Schemas define how an object is presented by defining the slots and their layouts
  61. JSP • Is the HTML Template normally for java web

    applications • We use tag libs from struts to add more behaviour to JSP.
  62. JSP @StrutsFunctionality(app = ExternalSupervisionConsultApp.class, path = "year", titleKey = "label.selectDegree.executionYear")

    @Mapping(path = "/viewYear", module = "externalSupervision") @Forwards({ @Forward(name = "selectYear", path = "/externalSupervision/consult/selectYear.jsp") }) public class ExternalSupervisorViewYearDA extends FenixDispatchAction { @EntryPoint public ActionForward beginTaskFlow(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { ExternalSupervisorViewsBean bean = new ExternalSupervisorViewsBean(); request.setAttribute("sessionBean", bean); return mapping.findForward("selectYear"); }
  63. JSP <fr:view name="sessionBean" property="students"> <fr:layout name="tabular-sortable"> <fr:property name="order(view-details)" value="1" />

    <fr:property name="key(view-details)" value="link.selectYear.viewStudentDetails" /> <fr:property name="bundle(view-details)" value="EXTERNAL_SUPERVISION_RESOURCES" /> <fr:property name="sortParameter" value="sortBy"/> <fr:property name="sortableSlots" value="istUsername,name, student.number"/> <fr:property name="classes" value="tstyle1 thleft" /> <fr:property name="headerClasses" value="acenter,acenter,,," /> <fr:property name="columnClasses" value="acenter,acenter,,,,," /> </fr:layout> <fr:schema type="net.sourceforge.fenixedu.domain.Person" bundle="EXTERNAL_SUPERVISION_RESOURCES"> <fr:slot name="student.number" key="label.selectYear.studentNumber" /> <fr:slot name="istUsername" key="label.selectYear.istUsername" /> <fr:slot name="name" key="label.selectYear.name" /> <fr:slot name="student.activeRegistrations" key="label.selectYear.degreeSigla"> <fr:property name="eachSchema" value="registration.view-degree-sigla"/> <fr:property name="eachLayout" value="values-comma"/> <fr:property name="classes" value="nobullet ulindent0 mvert0"/> </fr:slot> </fr:schema> </fr:view>
  64. Resource Bundles • For each module there is a resource

    bundle for each locale. Each file contains a list of strings internationalised for that locale. • Don’t write text directly in the JSPs. • Use the Resource Bundle Editor
  65. Renderers • Renderers also work the other way around. You

    can create forms for some type, and then, on the request get the object back.
  66. Renderers <fr:edit id="addAttendsBean" name="addAttendsBean" schema="AddAttendsBean" action="<%="/registration.do? method=addAttends&registrationId=" + registrationId %>">

    <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thright thlight mtop05"/> <fr:destination name="showForm" path="<%="/registration.do? method=prepareAddAttends&amp;registrationId=" + registrationId %>"/> </fr:layout> </fr:edit> /fenix/src/main/webapp/academicAdminOffice/student/registration/addAttends.jsp
  67. Renderers <schema name="AddAttendsBean" type="n.s.f.dataTransferObject.AddAttendsBean" bundle="APPLICATION_RESOURCES"> <slot name="executionDegree" layout=“menu-select-postback" validator="p.i.f.renderers.validators.RequiredValidator"> <property

    name="providerClass" value="n.s.f.p.renderers.providers.ExecutionDegreeForExecutionPeriodProvider" /> <property name="format" value="${presentationName}" /> <property name="destination" value="showForm"/> </slot> </schema> /fenix/src/main/webapp/WEB-INF/fenix/schemas/academicAdminOffice-schemas.xml
  68. Renderers @Mapping(path = "/registration", module = "academicAdministration", functionality = SearchForStudentsDA.class)

    @Forwards({@Forward(name = "addAttends", path = "/academicAdminOffice/student/registration/addAttends.jsp"),}) public class RegistrationDA extends StudentRegistrationDA { public ActionForward addAttends(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception { final Registration registration = getAndSetRegistration(request); request.setAttribute("registration", registration); final AddAttendsBean addAttendsBean = (AddAttendsBean) getObjectFromViewState("addAttendsBean"); final ExecutionCourse executionCourse = addAttendsBean.getExecutionCourse(); WriteStudentAttendingCourse.runWriteStudentAttendingCourse(registration, executionCourse.getExternalId()); return viewAttends(mapping, actionForm, request, response); } }
  69. Faces • It doesn’t have that much presence in FenixEdu.

    • We don’t do anything in faces, we are trying to remove it from FenixEdu (but still we have to maintain it)
  70. Servlet 2.3 <logic:present name="LOGGED_USER_ATTRIBUTE" property="person.homepage"> <logic:present name="LOGGED_USER_ATTRIBUTE" property="person.homepage.activated"> <logic:equal name="LOGGED_USER_ATTRIBUTE"

    property="person.homepage.activated" value="true"> <p> <bean:write name="LOGGED_USER_ATTRIBUTE" property=“person.homepage.fullPath"/>. </p> </logic:equal> </logic:present> </logic:present>
  71. Bennu Spring • If you are writing something from scratch,

    you should use Bennu Spring • Is fully compatible with Spring, meaning that you can use the same knowledge in here.
  72. Bennu Spring @BennuSpringController(AdminPortal.class) @RequestMapping("/cms/manage") public class AdminMenu { @RequestMapping(value="{slug}/menus", method

    = RequestMethod.GET) public String posts(Model model, @PathVariable(value="slug") String slug){ Site site = Site.fromSlug(slug); model.addAttribute("site", site); model.addAttribute("menus", site.getMenusSet()); return "menus"; } @SpringApplication(group = "anyone", path = "cms", title = "cms-manage") @SpringFunctionality(app = AdminPortal.class, title = "cms-manage") @RequestMapping("/cms/manage") public class AdminPortal { @RequestMapping(value = "{slug}/edit", method = RequestMethod.POST) public RedirectView edit(Model model, @PathVariable(value = "slug") String slug, @RequestParam String name, @RequestParam String description, @RequestParam String theme) { Site s = Site.fromSlug(slug); editSite(name, description, theme, s); return new RedirectView("/cms/manage", true); }
  73. REST APIs • HTTP Requests Methods (POST,GET, PUT,DELETE) • HTTP

    Status Codes (200, 404, 401, 403) • MediaType : application/json • Develop for life (once deployed it can never go offline)
  74. REST APIs Bennu Support • Endpoints extend org.fenixedu.bennu.core.rest. BennuRestResource •

    helper methods view, create and update • org.fenixedu.bennu.core.json.JsonAdapter are object handlers • implement view, create and update
  75. REST APIs JsonAdapter @DefaultJsonAdapter(User.class) public class UserJsonAdapter implements JsonAdapter<User> {

    @Override public JsonElement view(User user, JsonBuilder ctx) { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("id", user.getExternalId()); jsonObject.addProperty("username", user.getUsername()); jsonObject.addProperty("name", user.getPresentationName()); jsonObject.addProperty("active", !user.isLoginExpired()); LocalDate expiration = user.getExpiration(); if (expiration != null) { jsonObject.addProperty("expiration", ISODateTimeFormat.date().print(expiration)); } UserProfile profile = user.getProfile(); //FIXME: remove on the next major when profile is mandatory if (profile != null) { JsonUtils.put(jsonObject, "givenNames", profile.getGivenNames()); JsonUtils.put(jsonObject, "familyNames", profile.getFamilyNames()); JsonUtils.put(jsonObject, "displayName", profile.getDisplayName()); JsonUtils.put(jsonObject, "avatar", profile.getAvatarUrl()); } JsonUtils.put(jsonObject, "email", user.getEmail()); JsonUtils.put(jsonObject, "preferredLocale", ctx.view(user.getPreferredLocale())); return jsonObject; }
  76. Bennu REST Endpoint @Path("/bennu-core/users") public class UserResource extends BennuRestResource {

    @GET @Path("/{oid}") @Produces(MediaType.APPLICATION_JSON) public Response getUser(@PathParam("oid") String externalId) { return Response.ok(view(readDomainObject(externalId))).build(); } } • Endpoint available @ /api/bennu-core/users • Endpoints can be defined in any module. • What if oid doesn’t exist / not valid ? • readDomainObject -> throws exception with 404 (not found) status response
  77. Schedule Introduction Concepts Architecture Bennu Fenix Framework Struts & Renderers

    JSP & Renderers Faces & Spring New technologies Git & Maven Collaboration You are here
  78. AngularJS • Angular allows easy binding between the model and

    the view • You write the controllers that exchange information with the server • The view is automatically updated
  79. Java SE 8 represents the single largest evolution of the

    Java language in its history. A relatively small number of features (..) combine to offer a programming model that fuses the object-oriented and functional styles. Java Language Specification, Java SE 8
  80. Java 8 Lambda expressions Method References Default Methods Repeating annotations

    Type annotations Improved type inference Method parameter reflection Streams API HashMap improvements New monitoring tools Nashorn Java Mission Control New DateTime API LongAdders Optionals
  81. Lambda Expressions for (int i = 0; i < 1000;

    i++) { FenixFramework.getTransactionManager().withTransaction(new CallableWithoutException<Void>() { @Override public Void call() { FenixFramework.getDomainRoot().getCounterSet().add(new Counter()); return null; } }); } IntStream.range(0, 1000).parallel().forEach(i -> FenixFramework.atomic(() -> { FenixFramework.getDomainRoot().getCounterSet().add(new Counter()); }));
  82. Default Methods • Interfaces can now contain default methods! •

    These allow for API evolution without breaking backwards- compatibility default boolean removeIf(Predicate<? super E> f) { Objects.requireNonNull(f); (…) return removed; }
  83. Streams API • A stream is “A sequence of elements

    supporting sequential and parallel aggregate operations” • They provide fluent views of data streams (typically from collections) • Most operations are lazy people.stream().parallel(). map(Person::getName). filter(s -> s.startsWith(“João")). count(); people.forEach(p -> System.out.println(p) );
  84. Optionals • Optionals are a great way to avoid using

    null to convey ‘not present’ • Integrated with lambda expressions findPerson("João").ifPresent(j -> { System.out.println("Found him: " + j); }); findPerson("João").orElseGet(() -> new Person(“João") );
  85. SLF4J The Simple Logging Facade for Java (SLF4J) serves as

    a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time.
  86. SLF4J private static final Logger logger = LoggerFactory.getLogger(FenixInitializer.class); logger.info("Initializing Fenix”);

    logger.debug(“Got a request to URL {}”, url); logger.warn("Exception while closing connection", e);
  87. SLF4J • Always use SLF4J loggers • Choose the proper

    context for your logger (Typically its enclosing type) • Be careful when choosing the log level • Always use SLF4J formatter, this avoids allocating unnecessary strings
  88. Git • Distributed Version Control System • Branching is basically

    free - Use it! • Each clone is a full copy, you can do whatever you want • A ton of amazing tools: rebase, squash, amend, commit reordering, collaboration
  89. Git Branching • A git branch is merely a pointer

    to a commit • You can freely play around with it, you can even move some commits to another point in the branch • Two ways of merging: • Fast-Forward: Simply moving the branch pointer • Creating a merge node, which points to both heads
  90. Feature Branches • Your tasks/contributions should all be done in

    a feature branch • Once you start working, create a new branch from develop and give it a proper name (e.g. feature/ spaces-refactor) • Commit all your changes to your branch • Push it to your fork
  91. Git Branching Guidelines • Always keep your branches rebased! •

    We will not accept messy history due to bad rebases/merges • Always pay attention to the version in each branch • Keep track of all your remotes • Use git fetch + git rebase at all times, or git pull --rebase
  92. ~/.gitconfig [user] name = sergiofbsilva email = [email protected] [alias] ci

    = commit st = status co = checkout revert = "checkout -- " last = log -1 HEAD get = pull lsd = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative [color] ui = true [merge] renamelimit = 10000
  93. Maven • “Apache Maven is a software project management and

    comprehension tool.” • Much more than a build tool • Based around the concept of project • Convention over configuration • Each project has it’s own POM file
  94. Maven Projects • Have a unique name (Artifact ID), Group

    ID (we use org.fenixedu), version and packaging. • May declare a parent project (to avoid duplicating common configuration). We provide fenixedu- project, fenix-framework-project and web-app-project. • May declare additional plugins for various tasks • Declare the project’s dependencies - No binaries in the SCM!
  95. Maven Repositories • If the dependencies are not in the

    SCM, where are they? • Maven allows multiple repository • Maven Central - Most common java libs • FenixEdu Nexus - FenixEdu binaries • Proxied third-party - Caching of third-party repos
  96. Maven Projects • From the POM, Maven knows how to

    clean, build, install and deploy a project • Fenix Framework projects run a custom plugin to implement the code generation and injection steps
  97. mvn (clean) install Builds the project, and copies it to

    your local repository. Most suited for jar projects ~/.m2/repository
  98. Maven Tips • Always check the dependency versions • NEVER

    commit POMs with SNAPSHOT dependencies • Think twice before adding any dependencies • Java 8 and Guava provide many common tools • Don’t add dependencies that you don’t need • Install the Eclipse Maven Plugin (m2e)
  99. Fenix Framework Bennu Framework Bennu Core Bennu IO Bennu Scheduler

    Bennu Portal Bennu Renderers Bennu Spring Bankai Angular Persistence Web Infrastructure Presentation Application Modules FenixEdu (IST) FenixEdu Id Cards FenixEdu Core
  100. It’s Open! • Anyone can contribute code to FenixEdu •

    http://github.com/FenixEdu/<project> • Use Pull Requests, Submit issues.
  101. Code • Only code correctly formatted will be accepted into

    our repositories. • We will not format the code for you. Bad formatting is a rejection reason, period. • Use the EclipseFenixCodeStyle.xml file • Works on other IDEs
  102. On boarding • These rules are here to help you

    and us. • You’re not in Kansas anymore. You most likely never worked on a large group or a real life project. Your error will cost someone time. • Everyone screws up sometime. • Refer to this talk when you are doing administrative tasks (committing code, closing issues). FenixEdu Team O nly
  103. Database • You will have access to a Test database.

    • Access to this database is restricted and you can only connect to it using a SSL Tunnel. FenixEdu Team O nly
  104. Database • ssh -A -fNg -L <localport>:localhost:3306 [email protected] • mysql

    -h localhost -u<istid> --protocol=TCP -P <localport> -p<dbpass> <istid>_fenix -A FenixEdu Team O nly
  105. Database • Send us an email containing the following •

    ISTId • GitHub username • Your SSH Public Key FenixEdu Team O nly
  106. Database • You will receive an email with the dbpass,

    encrypted with your public SSH key. Instructions to decrypted it will be included. FenixEdu Team O nly
  107. Tasks • Tasks are issued to you from three ways.

    • Request Tracker • JIRA Issues • Directly FenixEdu Team O nly
  108. Request Tracker • Its the internal issue tracking system. It

    tracks everything from Academic Administrative Office requests from bugs. • RT Tickets are issued to you either by the Senior Staff or User Support Group. • After solving the ticket, give it back to who gave you. FenixEdu Team O nly
  109. Request Tracker • Do NOT Update Type to Reply To

    Requestors, EVER EVER! FenixEdu Team O nly
  110. Request Tracker • RT is a internal error management •

    External errors are managed in JIRA Issues • Internal errors SHOULD give rise to external errors when new functionalities are created or bugs are fixed FenixEdu Team O nly
  111. JIRA Issues • When you are creating a JIRA Issue

    originating from RT, you MUST NOT include private data (ISTId, OIDs, Names, Numbers, etc.) • You can create a Issue that someone outside the FenixEdu team solves. • You can create more than one Issue for a RT ticket. Learn to divide your problem in sub-problems. FenixEdu Team O nly
  112. Directly • Tasks may be given to you directly by

    the Senior Staff. • It is your responsibility to create a JIRA Issue regarding that functionality if one doesn’t exist, and close it when the functionality is done. FenixEdu Team O nly
  113. Understand & Act Design & Implement Is a bug or

    a feature? Create Jira Issue Missing Something? Jira Issue Issued FenixEdu Team O nly RT Ticket Assigned Close Issues Is From RT? Return RT Ticket to Issuer Request More Work Yup Yup Task given by Senior Staff Nop Nop
  114. Senior Staff • We have stuff to do, but we

    are here to help • You will get stuck in some parts. Not everything is easy to understand or documented. • ONLY bother us after you tried something. This will increase your knowledge of the system. “I don’t know” or “I haven’t tried” is not a good answer. FenixEdu Team O nly
  115. Senior Staff • This doesn’t mean don’t act. • If

    you are stuck, ask. • DO NOT bother Luis Cruz unless we say you so. He’s busy and has a lot more to do. FenixEdu Team O nly
  116. Documentation & Tests • You WILL write in confluence. •

    https://confluence.fenixedu.org/display/ACADEMIC/Getting+Started • New functionalities, particularly new modules MUST have comprehensive tests and documentation (JavaDoc, external documentation). FenixEdu Team O nly
  117. Code • Your code will be reviewed by us before

    being integrated. • You are on a public open source project. Your code will be read by other people, including future employers. Don’t write crap you aren’t comfortable showing off. FenixEdu Team O nly
  118. Github Features • Github Pull Requests • how we collaborate

    • easily integrate code among developers • automatic continuous integration system (travis) !
  119. Workspace • We normally use Eclipse, and Ubuntu. • We

    normally use Git on the console. • You can use whatever you want. • If you aren’t experienced with IDEs, large teams, or working on a professional environment, use what we use. If a solution exists for a problem, everyone benefits FenixEdu Team O nly
  120. Eclipse • Use Save Actions • Turn off Build Automatically.

    Doesn’t work that well. • Learn shortcuts. FenixEdu Team O nly