unable to set radio button in struts2 - user-interface

I am not able to get the value of radio button selected in a page
I have a JSP page as
<body>
<s:form action="/YYY" id="frmPersonalPage" name="frmPersonalPage" >
<s:radio name ="radio" list="skillMasterData"></s:radio>
</s:form>
</body>
This renders properly . In my struts.xml I have
<action name="YYY" class="com.tdi.atom.actions.CCC" method="showEditSkillMasterPage">
<result name ="success">/jsp/modules/skillmap/createskillmaster.jsp</result>
</action>
In my action class I have this
public class CCC extends BaseActionSupport {
private ArrayList skillMasterData;
public String radio;
private ArrayList l1;
private ArrayList l2;
private ArrayList l3;
public ArrayList getSkillMasterData() {
return skillMasterData;
}
public void setSkillMasterData(ArrayList skillMasterData) {
this.skillMasterData = skillMasterData;
}
public String showEditSkillMasterPage()
{ log.info("at showEditSkillMasterPage");
System.out.println("radio buttoneee : "+getRadio());//this is null
setEditType("EDIT");
return SUCCESS;
}
public String showListSkillMasterPage()
{
SkillMasterDB pddb =new SkillMasterDB();
JdbcHelper helper;
l1 =new ArrayList();
l2=new ArrayList();
l3=new ArrayList();
l1.add("asda");
l1.add("rqwrq");
l2.add("!####");
l2.add("9087907");
l3.add("./,/");
l3.add("[][][]");
skdto.add(l1);
skdto.add(l2);
skdto.add(l3);
setSkillMasterData(skdto);
return SUCCESS;
}
public String getRadio() {
return radio;
}
public void setRadio(String radio) {
this.radio = radio;
}
}
In BaseActionSupport class I have
public class BaseActionSupport extends ActionSupport implements SessionAware {
private Map userSession;
public UserDTO user;
public UserDTO getUser() {
return mgr.getUser();
}
public boolean isAdmin() {
return mgr.isUserADMIN();
}
public void setSession(Map session) {
userSession = session; mgr = new SecurityManager(userSession);
}
}
I just can't figure out why such simple code is not working. Else where very similar code works fine.

There are some strange things in your code.
Assuming CCC and YYY are obfuscated names created only for posting them here (otherwise, you should use CamelCase with first letter capitalized for class names, like MyAction),
you should respect JavaBeans conventions, then userSession should become session, because the accessors methods (getters and setters) should always respect the name of the private variable);
skdto variable is not initialized nor defined in your showListSkillMasterPage method;
I'm not sure if using ArrayList<ArrayList<String>> for radio button is good. You could try with a simple ArrayList<String>, like:
public String showListSkillMasterPage() {
SkillMasterDB pddb =new SkillMasterDB();
JdbcHelper helper;
List<String> skdto = new ArrayList<String>();
skdto.add("asda");
skdto.add("rqwrq");
skdto.add("!####");
skdto.add("9087907");
skdto.add("./,/");
skdto.add("[][][]");
setSkillMasterData(skdto);
return SUCCESS;
}
Finally, you can test with Firebug's Net module what is going out of your page, check the radio parameter value now and after the edit to see what is going wrong now and how it will be going (hopefully) right later...

Related

EF Core 5.0 How to manage multiple entity class with one generic repository

First question here, I hope I'm doing it right.
I'm using Entity Framework Core 5.0 (Code First) with an onion architecture (data/repo/service/mvc) and so I have a service for each table (almost).
It's work well but now I need to manage (get, insert, update, delete) about 150 tables which all have the same structure (Id, name, order).
I have added each of them as Entity class and their DbSet too in my DbContext, but I don't want to make 150 services, I would like to have a generic one .
How can I bind it to my generic repository ?
public class Repository<T> : IRepository<T> where T : BaseEntity
{
private readonly ApplicationContext context;
private DbSet<T> entities;
private readonly RepositorySequence repoSequence;
private string typeName { get; set; }
public Repository(ApplicationContext context)
{
this.context = context;
entities = context.Set<T>();
this.repoSequence = new RepositorySequence(context);
this.typeName = typeof(T).Name;
}
public T Get(long plng_Id)
{
return entities.SingleOrDefault(s => s.Id == plng_Id);
}
[...]
}
In an ideal world, would like to have something like this :
public async Task Insert(dynamic pdyn_Entity)
{
Type DynamicType = Type.GetType(pdyn_Entity);
Repository<DynamicType> vobj_Repo = new Repository<DynamicType>(mobj_AppContext);
long Id = await vobj_Repo.InsertAsync(pdyn_Entity);
}
But I can try to get type from DbSet string Name too, I just managed to retrieve some data :
public IEnumerable<object> GetAll(string pstr_DbSetName)
{
return ((IEnumerable<BaseEntity>)typeof(ApplicationContext).GetProperty(pstr_DbSetName).GetValue(mobj_AppContext, null));
}
I've tried the following method (2.0 compatible apparently) to get the good DbSet, not working neither (no Query) : https://stackoverflow.com/a/48042166/10359024
What am I missing?
Thanks a lot for your help
Not sure why you need to get type?
You can use something like this.
Repository.cs
public class Repository<T> : IRepository<T> where T : BaseEntity
{
private readonly ApplicationContext context;
private DbSet<T> entities;
public Repository(ApplicationContext context)
{
this.context = context;
entities = context.Set<T>();
}
public List<T> Get()
=> entities.ToList();
public T Get(long plng_Id)
=> entities.Find(plng_Id);
public long Save(T obj)
{
if (obj.ID > 0)
entities.Update(obj);
else
entities.Add(obj);
return obj.ID;
}
public void Delete(T obj)
=> entities.Remove(obj);
}
Then you can use either one of these 2 options you want
Multiple repositories following your tables
UserRepository.cs
public class UserRepository : Repository<User> : IUserRepository
{
private readonly ApplicationContext context;
public UserRepository(ApplicationContext context)
{
this.context = context;
}
}
BaseService.cs
public class BaseService : IBaseService
{
private readonly ApplicationContext context;
private IUserRepository user;
private IRoleRepository role;
public IUserRepository User { get => user ??= new UserRepository(context); }
public IRoleRepository Role { get => user ??= new RoleRepository(context); }
public BaseService(ApplicationContext context)
{
this.context = context;
}
}
If you are lazy to create multiple repositories, can use this way also. Your service just simple call Repository with entity name.
BaseService.cs
public class BaseService : IBaseService
{
private readonly ApplicationContext context;
private IRepository<User> user;
private IRepository<Role> role;
public IRepository<User> User { get => user ??= new Repository<User>(context); }
public IRepository<Role> Role { get => role ??= new Repository<Role>(context); }
public BaseService(ApplicationContext context)
{
this.context = context;
}
}
Finally, you can call service like this. You can use multiple services instead of BaseService if you want.
HomeController.cs
public class HomeController : Controller
{
private readonly IBaseService service;
public HomeController(IBaseService service)
{
this.service = service;
}
public IActionResult Index()
{
var user = service.User.Get();
return View(user);
}
public IActionResult Add(User user)
{
var id = service.User.Save(user);
return View();
}
}
I suggest to use first option (multiple repositories) because you may need to customise functions in own repository in future. And create service class following your controller name. For example, you have HomeController, UserController, etc. Create HomeService, UserService and link them with BaseService so that you can create customised functions in their own service class.
I assume you have a base entity like this:
public class BaseEntity
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Order { get; set; }
}
Then you can do CRUD operations in your generic repository like this:
public int Create(T item)
{
if (item == null) return 0;
entities.Add(item);////SaveChanges
return item.Id;
}
public void Update(T updatedItem)
{
context.SetModified(updatedItem);//SaveChanges
}
public IQueryable<T> All()
{
return entities();
}
And in each of the methods you have access to your 3 common fields in BaseEntity
Thank you all for your responses.
I need to have the type because I am using a blazor component which automatically binds to these tables. This component has the name of the desired entity class (in string) as a parameter. Thanks to #Asherguru's response I was able to find a way to do this:
1 - I made a 'SedgmentEntity' Class :
public abstract class SegmentEntity : ISegmentEntity
{
public abstract long Id { get; set; }
public abstract string Name { get; set; }
public abstract short? Order { get; set; }
}
2 - A SegmentRepository which is typed via Reflection:
public class SegmentRepository : ISegmentRepository
{
private readonly ApplicationContext context;
private readonly RepositorySequence repoSequence;
public SegmentRepository(ApplicationContext context)
{
this.context = context;
this.repoSequence = new RepositorySequence(context);
}
public async Task<long> Insert(string pstr_EntityType, SegmentEntity pobj_Entity)
{
Type? vobj_EntityType = Assembly.GetAssembly(typeof(SegmentEntity)).GetType("namespace.Data." + pstr_EntityType);
if (vobj_EntityType != null)
{
// create an instance of that type
object vobj_Instance = Activator.CreateInstance(vobj_EntityType);
long? nextId = await repoSequence.GetNextId(GetTableName(vobj_EntityType));
if (nextId == null)
{
throw new TaskCanceledException("Sequence introuvable pour " + vobj_EntityType.FullName);
}
PropertyInfo vobj_PropId = vobj_EntityType.GetProperty("Id");
vobj_PropId.SetValue(vobj_Instance, nextId.Value, null);
PropertyInfo vobj_PropName = vobj_EntityType.GetProperty("Name");
vobj_PropName.SetValue(vobj_Instance, pobj_Entity.Name, null);
PropertyInfo vobj_PropOrder = vobj_EntityType.GetProperty("Order");
vobj_PropOrder.SetValue(vobj_Instance, pobj_Entity.Order, null);
return ((SegmentEntity)context.Add(vobj_Instance).Entity).Id;
}
}
public IEnumerable<object> GetAll(string pstr_EntityType)
{
Type? vobj_EntityType = Assembly.GetAssembly(typeof(SegmentEntity)).GetType("namespace.Data." + pstr_EntityType);
if (vobj_EntityType != null)
{
PropertyInfo vobj_DbSetProperty = typeof(ApplicationContext).GetProperties().FirstOrDefault(prop =>
prop.PropertyType.FullName.Contains(vobj_EntityType.FullName));
return (IEnumerable<object>)vobj_DbSetProperty.GetValue(context, null);
}
return null;
}
}
I still have to handle the Get and the Delete functions but it should be fine.
Then I will be able to create a single service which will be called by my component.
Thanks again !

Is there something like #PostPostRequest?

I often want to refine posted data before use it, for example
public class Song() {
public String[] tags;
public String csvTags;
public void setTagsWithCsv() {
// this one should be more complicated for handling real data
this.tags = csvTags.split(",");
}
}
In this case, I have to call setTagsWithCsv method inside the method of the controller class.
#RequestMapping(value = "/song/create", method = POST)
public String createSong(Song song) {
song.setTagsWithCsv();
songService.create(song); // some code like this will come here
...
}
Is there any way to call the method with an annotation like '#PostConstruct'? The method should be called after a post request.
Maybe you just provided a bad example, but If your Song is in a form of POJO, you do it on a call to setCsvTags
public class Song {
private String[] tags;
private String csvTags;
public void setCsvTags(String csvTags) {
this.csvTags = csvTags;
this.tags = csvTags.split(",");
}
public void setTags(String[] tags) {
this.tags == tags;
String newCsvTags = Arrays.toString(tags);
this.csvTags = newCsvTags.substring(1, newCsvTags.length() - 1); // get rid of []
}
}
or make a method, without keeping explicit tags array
public class Song {
private String csvTags;
public void getTags() {
return csvTags.split(",");
}
}
Otherwise, there is no standard way of doing this, you can play with request interception before reaching your Controller, but I think it would be just a waste of time.

Wicket: Label with default text if model empty + CompoundPropertyModel

I have:
public FooPage( ... ) {
this.setDefaultModel( new CompoundPropertyModel(new GenericIdLDM( Foo.class, 1)) );
add(new Label("title"));
I'd like to have $subj.
I've found this solution from 2007 (point below) : http://www.mail-archive.com/wicket-user#lists.sourceforge.net/msg29603.html
However, it wouldn't work for CPM as it needs the constructor with model.
How could I make it work with CPM?
public class DefaultTextModel extends AbstractReadOnlyModel<String> {
private final IModel<String> delegate;
private final String def;
public DefaultTextModel(String def, IModel delegate) {
this.def = def;
this.delegate = delegate;
}
public String getObject() {
String s = delegate.getObject();
return (Strings.isEmpty(s)) ? def : s;
}
public void detach() {
delegate.detach();
}
}
You could have a custom Converter for your label. I think the better reflects your intentions as well. See for example https://cwiki.apache.org/WICKET/using-custom-converters.html#Usingcustomconverters-InWicket1.4
Other option could be JavaScript, check if the span is empty and then provide the default value.
I can override Label#initModel():
protected IModel<?> initModel() {
return new DefaultTextModel(defaultModel, super.initModel());
}
A simpler solution is to override Label#onComponentTagBody() and just apply the default text there.
(Sven Meier replied on the mailing list)

Spring 3 Custom Editor field replacement

Having my ValueObject
UserVO {
long id;
String username;
}
I created custom editor for parsing this object from string id#username
public class UserVOEditor extends PropertyEditorSupport {
#Override
public void setAsText(String text) throws IllegalArgumentException {
Preconditions.checkArgument(text != null,"Null argument supplied when parsing UserVO");
String[] txtArray = text.split("\\#");
Preconditions.checkArgument(txtArray.length == 2, "Error parsing UserVO. Expected: id#username");
long parsedId = Long.valueOf(txtArray[0]);
String username = txtArray[1];
UserVO uvo = new UserVO();
uvo.setUsername(username);
uvo.setId(parsedId);
this.setValue(uvo);
}
#Override
public String getAsText() {
UserVO uvo = (UserVO) getValue();
return uvo.getId()+'#'+uvo.getUsername();
}
in my controller i register
#InitBinder
public void initBinder(ServletRequestDataBinder binder) {
binder.registerCustomEditor(UserVO.class, new UserVOEditor());
}
having in my model object ModelVO
ModelVO {
Set<UserVO> users = new HashSet<UserVO>();
}
after custom editor is invoked all you can see after form submission is
ModelVO {
Set<String> users (linkedHashSet)
}
so when trying to iterate
for(UserVO uvo : myModel.getUser()){ .. }
Im having classCastException .. cannot cast 1234#username (String) to UserVO ..
HOW THIS MAGIC IS POSSIBLE ?
It is not magic, it is because of Generics will be only proved at compile time. So you can put every thing in a Set at runtime, no one will check if you put the correct type in the Set.
What you can try, to make spring a bit more clever, is to put the ModelVO in your command object.
<form:form action="whatEver" method="GET" modelAttribute="modelVO">
#RequestMapping(method = RequestMethod.GET)
public ModelAndView whatEver(#Valid ModelVO modelVO){
...
}

Problem using Stateful EJB in ManagedBean with RequestScope

I'm using JSF 2.0 and EJB 3.1 in the Glassfish v3 app server. And I'm facing actually the follwing problem:
In a MenagedBean with RequestScope I want to access a session object (an EJB with #Stateful) which should store some session relevant information as the seleced category, the seleced page (with a datatable paginator for each category), etc. - nothing special I think.
The first time a category is selected, the datatable is created and displayed. Allright so far.
Now, if an item (row) is clicked (to show the item's details) or if the next page should be displayed, the session (the stateful EJB) is recreated and again the default values are used to display and render the page.
The code looks like:
#ManagedBean
#RequestScoped
public class TableViewBean {
#EJB
SessionBean session;
public DataModel getTable() {
return session.getDataModel();
}
public SessionBean getSession(){
return session;
}
public void next() {
session.getPaginator().nextPage();
session.resetList();
}
public void previous() {
session.getPaginator().previousPage();
session.resetList();
}
// some other code
}
and the session EJB:
#Stateful
public class SessionBean {
private String selectedType = "Entity";
private DataModel dataModel;
private int rowsPerPage = 5;
private Paginator paginator;
public void setSelectedType(String type){
if(!type.equalsIgnoreCase(selectedType)){
selectedType = type;
updateService();
}
resetList();
}
public void resetList() {
dataModel = null;
}
public void resetPagination() {
paginator = null;
}
public int getRowsPerPage() {
return rowsPerPage;
}
public void setRowsPerPage(int rowsPerPage) {
this.rowsPerPage = rowsPerPage;
resetList();
resetPagination();
}
public Paginator getPaginator() {
if (paginator == null) {
paginator = new Paginator(rowsPerPage) {
#Override
public int getItemsCount() {
return selectedService.getCount();
}
#Override
public DataModel createPageDataModel() {
DataModel model = null;
if(selectedService != null){
model = new ListDataModel(....);
}
return model;
}
};
}
return paginator;
}
public DataModel getDataModel() {
if(dataModel == null){
dataModel = getPaginator().createPageDataModel();
}
return dataModel;
}
}
If I change the Scope of the ManagedBean to SessionScope everything works fine, but I don't like this, because of use of memory concerns.
What's wrong with my code...please help me.
Greetz, Gerry
Your RequestScoped ManagedBean is re-instantiated for each request (that's what RequestScoped means after all). Therefore, with each instantiation it gets injected with a new SFSB instance.

Resources